From 3a8a5c30ef41739055d39831201136bbd94966a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Sat, 5 Apr 2025 18:25:04 +0200 Subject: [PATCH] docs: use ConfigurationTab that allows switching between yaml, env and cmd. --- webpage/docs/configuration/README.md | 66 ++-- webpage/docs/configuration/authentication.md | 118 ++++--- webpage/docs/configuration/capture.md | 97 +++--- webpage/docs/configuration/desktop.md | 44 +-- webpage/docs/configuration/plugins.md | 36 +- webpage/docs/configuration/webrtc.md | 121 ++----- webpage/docs/migration-from-v2/README.md | 10 +- .../src/components/Configuration/index.tsx | 328 ++++++++++++------ 8 files changed, 430 insertions(+), 390 deletions(-) diff --git a/webpage/docs/configuration/README.md b/webpage/docs/configuration/README.md index 9dd1195b..f5127104 100644 --- a/webpage/docs/configuration/README.md +++ b/webpage/docs/configuration/README.md @@ -1,4 +1,6 @@ import { Def, Opt } from '@site/src/components/Anchor'; +import { ConfigurationTab } from '@site/src/components/Configuration'; +import configOptions from './help.json'; # Configuration @@ -291,17 +293,16 @@ import TabItem from '@theme/TabItem'; This is the initial configuration of the room that can be modified by an admin in real-time. -```yaml title="config.yaml" -session: - private_mode: false - locked_logins: false - locked_controls: false - control_protection: false - implicit_hosting: true - inactive_cursors: false - merciful_reconnect: true - heartbeat_interval: 120 -``` + - whether private mode is enabled, users do not receive the room video or audio. - whether logins are locked for users, admins can still login. @@ -316,18 +317,17 @@ session: This is the configuration of the neko server. -```yaml title="config.yaml" -server: - bind: "127.0.0.1:8080" - cert: "/path/to/cert.pem" - key: "/path/to/key.pem" - cors: [ "*" ] - metrics: true - path_prefix: "/neko" - pprof: true - proxy: true - static: "/var/www/neko" -``` + - address/port/socket to serve neko. For docker you might want to bind to `0.0.0.0` to allow connections from outside the container. - and paths to the SSL cert and key used to secure the neko server. If both are empty, the server will run in plain HTTP. @@ -345,14 +345,13 @@ server: This is the configuration of the logging system. -```yaml title="config.yaml" -log: - dir: - json: true - level: "info" - nocolor: true - time: "unix" -``` + - directory to store logs. If empty, logs are written to stdout. This is useful when running neko in a container. - when true, logs are written in JSON format. @@ -368,10 +367,7 @@ Shortcut environment variable to enable DEBUG mode: `NEKO_DEBUG=true` Here is a full configuration with default values as shown in the help command. Please refer to the sub-sections for more details. -import Configuration from '@site/src/components/Configuration'; -import configOptions from './help.json'; - - + ## Next Steps {#next} diff --git a/webpage/docs/configuration/authentication.md b/webpage/docs/configuration/authentication.md index 3fd1f758..a0c9962c 100644 --- a/webpage/docs/configuration/authentication.md +++ b/webpage/docs/configuration/authentication.md @@ -3,6 +3,8 @@ description: Configuration related to the Authentication and Sessions in Neko. --- import { Def, Opt } from '@site/src/components/Anchor'; +import { ConfigurationTab } from '@site/src/components/Configuration'; +import configOptions from './help.json'; # Authentication @@ -86,21 +88,25 @@ This provider allows you to define two types of users: **regular** users and **a Profiles for regular users and admins are optional, if not provided, the default profiles are used (see below in the example configuration). -```yaml title="config.yaml" -member: - provider: multiuser - multiuser: - # Password for admins, in plain text. - admin_password: "adminPassword" - # Profile fields as described above - admin_profile: - ... - # Password for regular users, in plain text. - user_password: "userPassword" - # Profile fields as described above - user_profile: - ... -``` +
See example configuration @@ -152,8 +158,8 @@ For easier configuration, you can specify only passwords using environment varia ```yaml title="docker-compose.yaml" environment: - NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "neko" NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: "admin" + NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "neko" ``` ::: @@ -161,15 +167,17 @@ environment: This provider reads the user's credentials from a file. It is useful for small deployments where you don't want to set up a database or LDAP server and still want to have persistent users. -```yaml title="config.yaml" -member: - provider: file - file: - # Absolute path to the file containing the users and their passwords. - path: /opt/neko/members.json - # Whether the passwords are hashed using sha256 or not. - hash: true -``` + It allows you to store the user's credentials in a JSON file. The JSON structure maps user logins to their passwords and profiles. @@ -239,18 +247,13 @@ You can leave the file empty and add users later using the HTTP API. This provider is the same as the file provider, but it saves the users only in memory. That means that the users are lost when the server is restarted. However, the default users can be set in the configuration file. The difference from the multi-user provider is that the users are not generated on demand and we define exactly which users with their passwords and profiles are allowed to log in. They cannot be logged in twice with the same username. -```yaml title="config.yaml" -member: - provider: object - object: - # List of users with their passwords and profiles - - username: "admin" - # Password in plain text - password: "admin" - # Profile fields as described above - profile: - ... -``` +
See example configuration @@ -296,10 +299,9 @@ member: This provider allows any user to log in without any authentication. It is useful for testing and development purposes. -```yaml title="config.yaml" -member: - provider: noauth -``` + :::danger Do not use this provider in production environments unless you know exactly what you are doing. It allows anyone to log in and control neko as an admin. @@ -311,10 +313,9 @@ Currently, there are only two providers available for sessions: **memory** and * Simply by specifying the `session.file` to a file path, the session provider will store the sessions in a file. Otherwise, the sessions are stored in memory and are lost when the server is restarted. -```yaml title="config.yaml" -session: - file: /opt/neko/sessions.json -``` + :::info In the future, we plan to add more session providers, such as Redis, PostgreSQL, etc. So the Configuration Options may change. @@ -324,10 +325,9 @@ In the future, we plan to add more session providers, such as Redis, PostgreSQL, The API User is a special user that is used to authenticate the HTTP API requests. It cannot connect to the room, but it can perform administrative tasks. The API User does not have a password but only a token that is used to authenticate the requests. If the token is not set, the API User is disabled. -```yaml title="config.yaml" -session: - api_token: "apiToken" -``` +', +}} comments={false} /> :::tip This user is useful in some situations when the rooms are generated by the server and the token is guaranteed to be random every time a short-lived room is run. It is not a good idea to define this token for long-lived rooms, as it can be stolen and used to perform administrative tasks. @@ -347,17 +347,15 @@ The authentication between the client and the server can be done using cookies o If you disable the cookies, the token will be sent to the client in the login response and saved in local storage. This is less secure than using cookies, as the token **can be stolen using XSS attacks**. Therefore, it is recommended to use cookies. ::: -```yaml title="config.yaml" -session: - cookie: - enabled: true - name: "NEKO_SESSION" - expiration: "24h" - secure: true - http_only: true - domain: "" - path: "" -``` + - - Whether the cookies are enabled or not. - - Name of the cookie used to store the session. diff --git a/webpage/docs/configuration/capture.md b/webpage/docs/configuration/capture.md index 2778c0d5..63949fb5 100644 --- a/webpage/docs/configuration/capture.md +++ b/webpage/docs/configuration/capture.md @@ -3,6 +3,8 @@ description: Configuration related to Gstreamer capture in Neko. --- import { Def, Opt } from '@site/src/components/Anchor'; +import { ConfigurationTab } from '@site/src/components/Configuration'; +import configOptions from './help.json'; # Audio & Video Capture @@ -27,22 +29,19 @@ All video pipelines must use the same video codec (defined in the " - codec: "vp8" # default video codec - ids: [ , , ... ] - pipelines: - : - : - ... -``` + - is the name of the [X display](https://www.x.org/wiki/) that you want to capture. If not specified, the environment variable `DISPLAY` will be used. - available codecs are `vp8`, `vp9`, `av1`, `h264`. [Supported video codecs](https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/WebRTC_codecs#supported_video_codecs) are dependent on the WebRTC implementation used by the client, `vp8` and `h264` are supported by all WebRTC implementations. - is a list of pipeline ids that are defined in the section. The first pipeline in the list will be the default pipeline. -- is a dictionary of pipeline configurations. Each pipeline configuration is defined by a unique pipeline id. They can be defined in two ways: either by building the pipeline dynamically using [Expression-Driven Configuration](#video.expression) or by defining the pipeline using a [Gstreamer Pipeline Description](#video.pipeline). +- is a shorthand for defining [Gstreamer pipeline description](#video.gst_pipeline) for a single pipeline. This is option is ignored if is defined. +- is a dictionary of pipeline configurations. Each pipeline configuration is defined by a unique pipeline id. They can be defined in two ways: either by building the pipeline dynamically using [Expression-Driven Configuration](#video.expression) or by defining the pipeline using a [Gstreamer Pipeline Description](#video.gst_pipeline). ### Expression-Driven Configuration {#video.expression} @@ -151,7 +150,7 @@ import TabItem from '@theme/TabItem';
-### Gstreamer Pipeline Description {#video.pipeline} +### Gstreamer Pipeline Description {#video.gst_pipeline} If you want to define the pipeline using a [Gstreamer pipeline description](https://gstreamer.freedesktop.org/documentation/tools/gst-launch.html?gi-language=c#pipeline-description), you can do so by setting the parameter. @@ -169,7 +168,7 @@ Since now you have to define the whole pipeline, you need to specify the src ele Your typical pipeline string would look like this: ``` -ximagesrc display-name={display} show-pointer=true use-damage=false ! ! appsink name=appsink" +ximagesrc display-name={display} show-pointer=true use-damage=false ! ! appsink name=appsink ``` See documentation for [ximagesrc](https://gstreamer.freedesktop.org/documentation/ximagesrc/index.html) and [appsink](https://gstreamer.freedesktop.org/documentation/app/appsink.html) for more information. @@ -258,13 +257,11 @@ Only one audio pipeline can be defined in neko. The audio pipeline is used to ca The Gstreamer pipeline is started when the first client requests the video stream and is stopped after the last client disconnects. -```yaml title="config.yaml" -capture: - audio: - device: "audio_output.monitor" # default audio device - codec: "opus" # default audio codec - pipeline: "" -``` + - is the name of the [pulseaudio device](https://wiki.archlinux.org/title/PulseAudio/Examples) that you want to capture. If not specified, the default audio device will be used. - available codecs are `opus`, `g722`, `pcmu`, `pcma`. [Supported audio codecs](https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/WebRTC_codecs#supported_audio_codecs) are dependent on the WebRTC implementation used by the client, `opus` is supported by all WebRTC implementations. @@ -293,23 +290,21 @@ Neko allows you to broadcast out-of-the-box the display and audio capture to a t The Gstreamer pipeline is started when the broadcast is started and is stopped when the broadcast is stopped regardless of the clients connected. -```yaml title="config.yaml" -capture: - broadcast: - audio_bitrate: 128 # in KB/s - video_bitrate: 4096 # in KB/s - preset: "veryfast" - pipeline: "" - url: "rtmp:////" - autostart: true -``` + The default encoder uses `h264` for video and `aac` for audio, muxed in the `flv` container and sent over the `rtmp` protocol. You can change the encoder settings by setting a custom Gstreamer pipeline description in the parameter. - and are the bitrate settings for the default audio and video encoders expressed in kilobits per second. - is the encoding speed preset for the default video encoder. See available presets [here](https://gstreamer.freedesktop.org/documentation/x264/index.html?gi-language=c#GstX264EncPreset). - when set, encoder settings above are ignored and the custom Gstreamer pipeline description is used. In the pipeline, you can use `{display}`, `{device}` and `{url}` as placeholders for the X display name, pulseaudio audio device name, and broadcast URL respectively. -- is the URL of the RTMP server where the broadcast will be sent. This can be set later using the API if the URL is not known at the time of configuration or is expected to change. +- is the URL of the RTMP server where the broadcast will be sent e.g. `rtmp:////`. This can be set later using the API if the URL is not known at the time of configuration or is expected to change. - is a boolean value that determines whether the broadcast should start automatically when neko starts, works only if the URL is set.
@@ -380,14 +375,12 @@ This is a fallback mechanism and should not be used as a primary video stream be The Gstreamer pipeline is started in the background when the first client requests the screencast and is stopped after a period of inactivity. -```yaml title="config.yaml" -capture: - screencast: - enabled: true - rate: "10/1" - quality: 60 - pipeline: "" -``` + - is a boolean value that determines whether the screencast is enabled or not. - is the framerate of the screencast. It is expressed as a fraction of frames per second, for example, `10/1` means 10 frames per second. @@ -422,14 +415,12 @@ Neko allows you to capture the webcam on the client machine and send it to the s The Gstreamer pipeline is started when the client shares their webcam and is stopped when the client stops sharing the webcam. Maximum one webcam pipeline can be active at a time. -```yaml title="config.yaml" -capture: - webcam: - enabled: true - device: "/dev/video0" # default webcam device - width: 640 - height: 480 -``` + - is a boolean value that determines whether the webcam capture is enabled or not. - is the name of the [video4linux device](https://www.kernel.org/doc/html/v4.12/media/v4l-drivers/index.html) that will be used as a virtual webcam. @@ -463,12 +454,10 @@ Neko allows you to capture the microphone on the client machine and send it to t The Gstreamer pipeline is started when the client shares their microphone and is stopped when the client stops sharing the microphone. Maximum one microphone pipeline can be active at a time. -```yaml title="config.yaml" -capture: - microphone: - enabled: true - device: "audio_input" -``` + - is a boolean value that determines whether the microphone capture is enabled or not. - is the name of the [pulseaudio device](https://wiki.archlinux.org/title/PulseAudio/Examples) that will be used as a virtual microphone. diff --git a/webpage/docs/configuration/desktop.md b/webpage/docs/configuration/desktop.md index d1a3f47f..b492e9ce 100644 --- a/webpage/docs/configuration/desktop.md +++ b/webpage/docs/configuration/desktop.md @@ -3,6 +3,8 @@ description: Configuration related to the Desktop Environment in Neko. --- import { Def, Opt } from '@site/src/components/Anchor'; +import { ConfigurationTab } from '@site/src/components/Configuration'; +import configOptions from './help.json'; # Desktop Environment @@ -10,18 +12,15 @@ This section describes how to configure the desktop environment inside neko. Neko uses the [X Server](https://www.x.org/archive/X11R7.6/doc/man/man1/Xserver.1.xhtml) as the display server with [Openbox](http://openbox.org/wiki/Main_Page) as the default window manager. For audio, [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/) is used. -```yaml title="config.yaml" -desktop: - display: "" - screen: "1280x720@30" # default -``` + - refers to the X server that is running on the system. If it is not specified, the environment variable `DISPLAY` is used. The same display is referred to in the [Capture](capture#video.display) configuration to capture the screen. In most cases, we want to use the same display for both. - refers to the screen resolution and refresh rate. The format is `x@`. If not specified, the default is `1280x720@30`. :::tip -You can specify the screen resolution using the environment variable `NEKO_DESKTOP_SCREEN`. - Admin can change the resolution in the GUI. ::: @@ -33,12 +32,10 @@ Neko uses the [XTEST Extension Library](https://www.x.org/releases/X11R7.7/doc/l Currently, only touchscreens are supported through the custom driver. ::: -```yaml title="config.yaml" -desktop: - input: - enabled: true # default - socket: "/tmp/xf86-input-neko.sock" # default -``` + - enables the input device support. If not specified, the default is `false`. - refers to the socket file that the custom driver creates. If not specified, the default is `/tmp/xf86-input-neko.sock`. @@ -51,10 +48,9 @@ When using Docker, the custom driver is already included in the image and the so Most of the time, only a single application is used in the minimal desktop environment without any taskbar or desktop icons. It could happen that the user accidentally minimizes the application and then it is not possible to restore it. To prevent this, we can use the `unminimize` feature that simply listens for the minimize event and restores the window back to the original state. -```yaml title="config.yaml" -desktop: - unminimize: true # default -``` + ## Upload Drop {#upload_drop} @@ -62,10 +58,9 @@ The upload drop is a feature that allows the user to upload files to the applica The current approach is to catch the drag and drop events on the client side, upload them to the server along with the coordinates of the drop event, and then open an invisible overlay window on the server that has set the file path to the uploaded file and allows it to be dragged and dropped into the application. Then the mouse events are simulated to drag the file from the overlay window to the application window. -```yaml title="config.yaml" -desktop: - upload_drop: true # default -``` + ## File Chooser Dialog {#file_chooser_dialog} @@ -77,7 +72,6 @@ The file chooser dialog is a feature that allows handling the file chooser dialo The current approach is to put the file chooser dialog in the background as soon as it is displayed, prompt the user to upload the file, and then select this file in the file chooser dialog by simulating the keyboard events to navigate to the file and press the open button. **This is very error-prone and may not work as expected.** -```yaml title="config.yaml" -desktop: - file_chooser_dialog: false # default -``` + diff --git a/webpage/docs/configuration/plugins.md b/webpage/docs/configuration/plugins.md index 9d6fc85a..5f6d5e38 100644 --- a/webpage/docs/configuration/plugins.md +++ b/webpage/docs/configuration/plugins.md @@ -3,17 +3,18 @@ description: Configuration related to the Neko plugins. --- import { Def, Opt } from '@site/src/components/Anchor'; +import { ConfigurationTab } from '@site/src/components/Configuration'; +import configOptions from './help.json'; # Plugins Configuration Neko allows you to extend its functionality by using [plugins](https://pkg.go.dev/plugin). Go plugins come with a lot of benefits as well as some limitations. The main advantage is that you can extend the functionality of the application without recompiling the main application. But the main limitation is that you need to use the same Go version and all dependencies with the same version as the main application. -```yaml title="config.yaml" -plugins: - enabled: true - required: true - dir: "./bin/plugins" -``` + - enables the plugin support. If set to `false`, the plugins are not loaded. - makes the plugin loading mandatory, meaning that if a plugin fails to load, the application will not start. @@ -29,10 +30,9 @@ There exist a few pre-loaded internal plugins that are shipped with Neko: The chat plugin is a simple pre-loaded internal plugin that allows you to chat with other users in the same session. The chat messages are sent to the server and then broadcasted to all users in the same session. -```yaml title="config.yaml" -chat: - enabled: true -``` + - enables the chat support. If set to `false`, the chat is disabled. @@ -51,12 +51,15 @@ plugins: The file transfer plugin is a simple pre-loaded internal plugin that allows you to transfer files between the client and the server. The files are uploaded to the server and then downloaded by the client. -```yaml title="config.yaml" -filetransfer: - enabled: true - dir: "./uploads" - refresh_interval: 30s -``` + + - enables the file transfer support. If set to `false`, the file transfer is disabled. - refers to the directory where the files are stored. @@ -70,4 +73,3 @@ plugins: ``` - `filetransfer.enabled` in the room settings context controls whether the file transfer is enabled for any user in the room, and in the user's profile context controls whether the user can transfer files. - diff --git a/webpage/docs/configuration/webrtc.md b/webpage/docs/configuration/webrtc.md index 47c5face..6606480f 100644 --- a/webpage/docs/configuration/webrtc.md +++ b/webpage/docs/configuration/webrtc.md @@ -3,6 +3,8 @@ description: Configuration related to the WebRTC and Networking in Neko. --- import { Def, Opt } from '@site/src/components/Anchor'; +import { ConfigurationTab } from '@site/src/components/Configuration'; +import configOptions from './help.json'; # WebRTC Configuration @@ -18,19 +20,17 @@ ICE, which stands for Interactive Connectivity Establishment, is a protocol used ICE Trickle is a feature that allows ICE candidates to be sent as they are discovered, rather than waiting for all candidates to be discovered before sending them. It means that the ICE connection can be established faster as the server can start connecting to the client as soon as it has a few ICE candidates and doesn't have to wait for all of them to be discovered. -```yaml title="config.yaml" -webrtc: - icetrickle: false -``` + ### ICE Lite {#icelite} ICE Lite is a minimal implementation of the ICE protocol intended for servers running on a public IP address. It is not enabled by default to allow more complex ICE configurations out of the box. -```yaml title="config.yaml" -webrtc: - icelite: false -``` + :::info When using ICE Servers, ICE Lite must be disabled. @@ -100,16 +100,10 @@ import TabItem from '@theme/TabItem'; The ICE servers are divided into two groups: -```yaml title="config.yaml" -webrtc: - iceservers: - frontend: - # List of ICE Server configurations as described above - - urls: "stun:stun.l.google.com:19302" - backend: - # List of ICE Server configurations as described above - - urls: "stun:stun.l.google.com:19302" -``` + - - ICE servers that are sent to the client and used to establish a connection between the client and the server. - - ICE servers that are used by the server to gather ICE candidates. They might contain private IP addresses or other sensitive information that should not be sent to the client. @@ -162,15 +156,14 @@ There exist two types of connections: The ephemeral UDP port range can be configured using the following configuration: -```yaml title="config.yaml" -webrtc: - epr: "59000-59100" -``` + The range `59000-59100` contains 101 ports, which should be open on the server's firewall. The server uses these ports to establish a connection with the client. You can specify a different range of ports if needed, with fewer or more ports, depending on the number of simultaneous connections you expect. -:::tip -You can specify the ephemeral UDP port range as an environment variable in the `docker-compose.yaml` file using the `NEKO_WEBRTC_EPR` environment variable. When using docker, make sure to expose the ports in the `docker-compose.yaml`. +:::tip Make sure +When specifying the ephemeral UDP port range in `docker-compose.yaml`, make sure to use the same range for ports **as UDP**. ```yaml title="docker-compose.yaml" environment: @@ -186,19 +179,18 @@ It is important to expose the same ports to the host machine, without any remapp The UDP/TCP multiplexing port can be configured using the following configuration: -```yaml title="config.yaml" -webrtc: - udpmux: 59000 - tcpmux: 59000 -``` + - - The port used for UDP connections. - - The port used for TCP connections. The server uses only port `59000` for both UDP and TCP connections. This port should be open on the server's firewall. You can specify a different port if needed, or specify only one of the two protocols. UDP is generally better for latency, but some networks block UDP so it is good to have TCP available as a fallback. -:::tip -You can specify the UDP/TCP multiplexing port as an environment variable in the `docker-compose.yaml` file using the `NEKO_WEBRTC_TCPMUX` and `NEKO_WEBRTC_UDPMUX` environment variables. When using docker, make sure to expose the ports in the `docker-compose.yaml`. +:::tip Make sure +When specifying the UDP/TCP multiplexing port in `docker-compose.yaml`, make sure to correctly specify the protocol in the ports section. ```yaml title="docker-compose.yaml" environment: @@ -217,42 +209,20 @@ It is important to expose the same ports to the host machine, without any remapp The server IP address is sent to the client in ICE candidates so that the client can establish a connection with the server. By default, the server IP address is automatically resolved by the server to the public IP address of the server. If the server is behind a NAT, you want to specify a different IP address or use neko only in a local network, you can specify the server IP address manually. #### NAT 1-to-1 {#nat1to1} + -```yaml title="config.yaml" -webrtc: - nat1to1: - # IPv4 address of the server - - 10.10.0.5 - # IPv6 address of the server - - 2001:db8:85a3::8a2e:370:7334 -``` - -Currently, only one IPv4 and one IPv6 address can be specified. Therefore if you want to access your instance from both local and public networks, your router must support [NAT loopback (hairpinning)](https://en.wikipedia.org/wiki/Network_address_translation#NAT_hairpinning). - -:::tip -You can specify the server IP address as an environment variable in the `docker-compose.yaml` file using the `NEKO_WEBRTC_NAT1TO1` environment variable. - -```yaml title="docker-compose.yaml" -environment: - NEKO_WEBRTC_NAT1TO1: "10.10.0.5" -``` - -If you want to specify also an IPv6 address, use whitespace to separate the addresses. - -```yaml title="docker-compose.yaml" -environment: - NEKO_WEBRTC_NAT1TO1: "10.10.0.5 2001:db8:85a3::8a2e:370:7334" -``` -::: +Currently, only one address can be specified. Therefore if you want to access your instance from both local and public networks, your router must support [NAT loopback (hairpinning)](https://en.wikipedia.org/wiki/Network_address_translation#NAT_hairpinning). #### IP Retrieval URL {#ip_retrieval_url} If you do not specify the server IP address, the server will try to resolve the public IP address of the server automatically. -```yaml title="config.yaml" -webrtc: - ip_retrieval_url: "https://checkip.amazonaws.com" -``` + + The server will send an HTTP GET request to the specified URL to retrieve the public IP address of the server. ## Bandwidth Estimator {#estimator} @@ -263,29 +233,6 @@ The bandwidth estimator is an experimental feature and might not work as expecte The bandwidth estimator is a feature that allows the server to estimate the available bandwidth between the client and the server. It is used to switch between different video qualities based on the available bandwidth. The bandwidth estimator is disabled by default. -```yaml title="config.yaml" -webrtc: - estimator: - # Whether to enable the bandwidth estimator - enabled: false - # Whether the bandwidth estimator is passive - only used for logging and not for actual decisions - passive: false - # Enable debug logging for the bandwidth estimator (will print the current state and decisions) - debug: false - # Initial bitrate for the bandwidth estimator to start with (in bps) - initial_bitrate: 1000000 - # How often to read and process bandwidth estimation reports - read_interval: "2s" - # How long to wait for a stable connection (upward or neutral trend) before upgrading - stable_duration: "12s" - # How long to wait for a stalled connection (neutral trend with low bandwidth) before downgrading - unstable_duration: "6s" - # How long to wait for stalled bandwidth estimation before downgrading - stalled_duration: "24s" - # How long to wait before downgrading again after the previous downgrade - downgrade_backoff: "10s" - # How long to wait before upgrading again after the previous upgrade - upgrade_backoff: "5s" - # How much bigger the difference between estimated and stream bitrate must be to trigger a change - diff_threshold: 0.15 -``` + diff --git a/webpage/docs/migration-from-v2/README.md b/webpage/docs/migration-from-v2/README.md index 7dd8114d..d8f10d53 100644 --- a/webpage/docs/migration-from-v2/README.md +++ b/webpage/docs/migration-from-v2/README.md @@ -58,9 +58,9 @@ See the V3 configuration options for the [WebRTC Video](/docs/v3/configuration/c | `NEKO_VP8=true` *deprecated* | `NEKO_CAPTURE_VIDEO_CODEC=vp8` | | `NEKO_VP9=true` *deprecated* | `NEKO_CAPTURE_VIDEO_CODEC=vp9` | | `NEKO_VIDEO` | `NEKO_CAPTURE_VIDEO_PIPELINE`, V3 allows multiple video pipelines | -| `NEKO_VIDEO_BITRATE` | **removed**, use [custom pipeline](/docs/v3/configuration/capture#video.pipeline) instead | -| `NEKO_HWENC` | **removed**, use [custom pipeline](/docs/v3/configuration/capture#video.pipeline) instead | -| `NEKO_MAX_FPS` | **removed**, use [custom pipeline](/docs/v3/configuration/capture#video.pipeline) instead | +| `NEKO_VIDEO_BITRATE` | **removed**, use [custom pipeline](/docs/v3/configuration/capture#video.gst_pipeline) instead | +| `NEKO_HWENC` | **removed**, use [custom pipeline](/docs/v3/configuration/capture#video.gst_pipeline) instead | +| `NEKO_MAX_FPS` | **removed**, use [custom pipeline](/docs/v3/configuration/capture#video.gst_pipeline) instead | :::warning Limitation @@ -133,10 +133,10 @@ See the V3 configuration options for the [WebRTC](/docs/v3/configuration/webrtc) Here is a full list of all the configuration options available in Neko V2 that are still available in Neko V3 with legacy support enabled. -import Configuration from '@site/src/components/Configuration'; +import { ConfigurationTab } from '@site/src/components/Configuration'; import configOptions from './help.json'; - + See the full [V3 configuration reference](/docs/v3/configuration/#full) for more details. diff --git a/webpage/src/components/Configuration/index.tsx b/webpage/src/components/Configuration/index.tsx index 1497cd87..79f2422c 100644 --- a/webpage/src/components/Configuration/index.tsx +++ b/webpage/src/components/Configuration/index.tsx @@ -3,130 +3,244 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; -interface ConfigOption { - key: string[]; - description: string; - defaultValue?: string; +interface ConfigOptionValue { type?: string; + description?: string; + defaultValue?: string; } -interface ConfigurationTabProps { - configOptions: ConfigOption[]; +interface ConfigOption extends ConfigOptionValue { + key: string[]; } -const ConfigurationTab: React.FC = ({ configOptions }) => { - const environmentVariables = () => { - let code = ''; - configOptions.forEach(option => { - let value = "" - if (option.defaultValue) { - value = `"${option.defaultValue}"` - } else if (option.type) { - value = `<${option.type}>` - } - code += `# ${option.description}\n`; - code += `NEKO_${option.key.join('_').toUpperCase()}: ${value}\n`; - }); - return ( - - {code} - - ); +function configKey(key: string | string[], value: ConfigOptionValue | any): ConfigOption { + if (typeof key === 'string') { + key = key.split('.'); + } + if (typeof value === 'object') { + return { + key, + type: value.type || getType(value.defaultValue), + description: value.description, + defaultValue: value.defaultValue, + } + } else { + return { + key, + type: getType(value), + defaultValue: value, + } + } +} + +function configKeys(optValues: Record): ConfigOption[] { + let options: ConfigOption[] = []; + Object.entries(optValues).forEach(([key, value]) => { + options.push(configKey(key, value)); + }); + return options; +} + +function filterKeys(options: ConfigOption[], filter: string): ConfigOption[] { + return options.filter(option => { + const key = option.key.join('.'); + return key.startsWith(filter) + }); +} + +function defaultValue(value: ConfigOptionValue): string { + switch (value.type) { + case 'boolean': + return `${value.defaultValue || false}`; + case 'int': + case 'float': + case 'number': + return `${value.defaultValue || 0}`; + case 'duration': + case 'string': + return `${value.defaultValue ? `"${value.defaultValue}"` : ''}`; + case 'strings': + return ''; + case 'object': + return ''; + case 'array': + return ''; + default: + return value.type ? `<${value.type}>` : ''; + } +} + +function getType(value: any): string { + if (Array.isArray(value)) { + return 'array'; + } + return typeof value; +} + +export function EnvironmentVariables({ options, comments, ...props }: { options: ConfigOption[], comments?: boolean }) { + if (typeof comments === 'undefined') { + comments = true; } - const cmdArguments = () => { - let code = ''; - configOptions.forEach(option => { - code += `# ${option.description}\n`; - code += `--${option.key.join('.')}`; - if (option.type) { - code += ` <${option.type}>`; - } - code += '\n'; - }); - return ( - - {code} - - ); + let code = ''; + options.forEach(option => { + const description = option.description ? option.description : ''; + const type = option.type ? ` (${option.type})` : ''; + if (comments && description) { + code += `# ${description}${type}\n`; + } + code += `NEKO_${option.key.join('_').toUpperCase()}=${defaultValue(option)}\n`; + }); + + return ( + + {code} + + ); +} + +export function CommandLineArguments({ options, comments, ...props }: { options: ConfigOption[], comments?: boolean }) { + if (typeof comments === 'undefined') { + comments = true; } - const yamlFile = () => { - const final = Symbol('final'); - - const buildYaml = (obj, prefix = '') => { - let code = ''; - Object.keys(obj).forEach(key => { - const value = obj[key]; - if (typeof value === 'object' && !Array.isArray(value) && !value[final]) { - code += prefix+`${key}:\n`; - code += buildYaml(value, prefix + ' '); + let code = ''; + options.forEach(option => { + const description = option.description ? option.description : ''; + const type = option.type ? ` (${option.type})` : ''; + if (comments && description) { + code += `# ${description}${type}\n`; + } + code += `--${option.key.join('.')} ${defaultValue(option)}\n`; + }); + + return ( + + {code} + + ); +} + +export function YamlFileContent({ options, comments, ...props }: { options: ConfigOption[], comments?: boolean }) { + if (typeof comments === 'undefined') { + comments = true; + } + + const final = Symbol('final'); + + const buildYaml = (obj: Record, prefix = '') => { + let code = ''; + Object.entries(obj).forEach(([key, option]) => { + if (typeof option === 'object' && !Array.isArray(option) && !option[final]) { + code += prefix+`${key}:\n`; + code += buildYaml(option, prefix + ' '); + } else { + const description = option.description ? option.description : ''; + const type = option.type ? ` (${option.type})` : ''; + if (comments && description) { + code += `${prefix}# ${description}${type}\n`; + } + let value: string; + if (option.type === 'strings') { + value = option.defaultValue ? `[ "${option.defaultValue}" ]` : '[ ]'; + } else if (option.type === 'object') { + value = "{}" + } else if (option.type === 'array') { + value = "[]" } else { - let val = ''; - switch (value.type) { - case 'boolean': - val = `${value.defaultValue || false}`; - break; - case 'int': - case 'float': - val = `${value.defaultValue || 0}`; - break; - case 'strings': - val = `[ ${value.defaultValue ? value.defaultValue.map(v => `"${v}"`).join(', ') : ''} ]`; - break; - case 'duration': - case 'string': - val = `${value.defaultValue ? `"${value.defaultValue}"` : ''}`; - break; - default: - val = `<${value.type}>`; - break; - } - code += prefix+`# ${value.description || ''}\n`; - code += prefix+`${key}: ${val}\n`; + value = defaultValue(option); } - }); - return code; - }; + code += `${prefix}${key}: ${value}\n`; + } + }); + return code; + }; - const yamlCode = buildYaml(configOptions.reduce((acc, option) => { - const keys = option.key; - let current = acc; - keys.forEach((key, index) => { - if (!current[key]) { - current[key] = index === keys.length - 1 ? option : {}; - } - current = current[key]; - }); - current[final] = true; - return acc; - }, {})); + const yamlCode = buildYaml(options.reduce((acc, option) => { + const keys = option.key; + let current = acc; + keys.forEach((key, index) => { + if (!current[key]) { + current[key] = index === keys.length - 1 ? option : {}; + } + current = current[key]; + }); + current[final] = true; + return acc; + }, {})); - return ( - - {yamlCode} - - ); + return ( + + {yamlCode} + + ); +} + +type ConfigurationTabProps = { + options?: ConfigOption[] | Record; + heading?: boolean; + comments?: boolean; + filter?: string | string[] | Record; +}; + +export function ConfigurationTab({ options, heading, comments, filter, ...props }: ConfigurationTabProps) { + var configOptions: ConfigOption[] = []; + if (Array.isArray(options)) { + configOptions = options; + } else { + configOptions = configKeys(options) + } + if (typeof comments === 'undefined') { + comments = true; + } + if (typeof heading === 'undefined') { + heading = false; + } + + if (Array.isArray(filter)) { + let filteredOptions: ConfigOption[] = []; + for (const f of filter) { + filteredOptions = [ ...filteredOptions, ...filterKeys(configOptions, f) ]; + } + configOptions = filteredOptions; + } else if (typeof filter === 'string') { + configOptions = filterKeys(configOptions, filter); + } else if (typeof filter === 'object') { + let filteredOptions: ConfigOption[] = []; + for (const k in filter) { + let filtered = configOptions.find(option => { + return option.key.join('.') === k; + }); + let replaced = configKey(k, filter[k]); + filteredOptions = [ ...filteredOptions, { ...filtered, ...replaced } ]; + } + configOptions = filteredOptions; } return ( -
- - + + + {heading && (

You can set the following environment variables in your docker-compose.yaml file or in your shell environment.

- {environmentVariables()} -
- + )} + {EnvironmentVariables({ options: configOptions, comments })} + + + {heading && (

You can list the following command line arguments using neko serve --help.

- {cmdArguments()} -
- + )} + {CommandLineArguments({ options: configOptions, comments })} + + + {heading && (

You can create a /etc/neko/neko.yaml file with the following configuration options.

- {yamlFile()} -
-
-
+ )} + {YamlFileContent({ options: configOptions, comments })} + + ); -}; - -export default ConfigurationTab; +}