Compare commits
16 Commits
split-cont
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
d1f1be4e86 | ||
|
e754e66878 | ||
|
26af1dc7f5 | ||
|
0c9055e4f6 | ||
|
c200326512 | ||
|
b1ce755210 | ||
|
2b13220d63 | ||
|
db6f9c957e | ||
|
798bf579c0 | ||
|
2f9964580f | ||
|
b8881b3a46 | ||
|
355c0eac0d | ||
|
4d023df692 | ||
|
792b1ac111 | ||
|
a03b29ba01 | ||
|
683b750189 |
@ -10,7 +10,7 @@ RUN set -eux; \
|
|||||||
#
|
#
|
||||||
# install widevine module
|
# install widevine module
|
||||||
CHROMIUM_DIR="/usr/lib/chromium"; \
|
CHROMIUM_DIR="/usr/lib/chromium"; \
|
||||||
WIDEVINE_VERSION=$(wget --quiet -O - https://dl.google.com/widevine-cdm/versions.txt | tail -n 1); \
|
WIDEVINE_VERSION=$(wget --quiet -O - https://dl.google.com/widevine-cdm/versions.txt | sort --version-sort | tail -n 1); \
|
||||||
wget -O /tmp/widevine.zip "https://dl.google.com/widevine-cdm/${WIDEVINE_VERSION}-linux-x64.zip"; \
|
wget -O /tmp/widevine.zip "https://dl.google.com/widevine-cdm/${WIDEVINE_VERSION}-linux-x64.zip"; \
|
||||||
mkdir -p "${CHROMIUM_DIR}/WidevineCdm/_platform_specific/linux_x64"; \
|
mkdir -p "${CHROMIUM_DIR}/WidevineCdm/_platform_specific/linux_x64"; \
|
||||||
unzip -p /tmp/widevine.zip LICENSE.txt > "${CHROMIUM_DIR}/WidevineCdm/LICENSE"; \
|
unzip -p /tmp/widevine.zip LICENSE.txt > "${CHROMIUM_DIR}/WidevineCdm/LICENSE"; \
|
||||||
|
@ -14,7 +14,7 @@ RUN set -eux; \
|
|||||||
#
|
#
|
||||||
# install widevine module
|
# install widevine module
|
||||||
CHROMIUM_DIR="/usr/lib/chromium"; \
|
CHROMIUM_DIR="/usr/lib/chromium"; \
|
||||||
WIDEVINE_VERSION=$(wget --quiet -O - https://dl.google.com/widevine-cdm/versions.txt | tail -n 1); \
|
WIDEVINE_VERSION=$(wget --quiet -O - https://dl.google.com/widevine-cdm/versions.txt | sort --version-sort | tail -n 1); \
|
||||||
wget -O /tmp/widevine.zip "https://dl.google.com/widevine-cdm/${WIDEVINE_VERSION}-linux-x64.zip"; \
|
wget -O /tmp/widevine.zip "https://dl.google.com/widevine-cdm/${WIDEVINE_VERSION}-linux-x64.zip"; \
|
||||||
mkdir -p "${CHROMIUM_DIR}/WidevineCdm/_platform_specific/linux_x64"; \
|
mkdir -p "${CHROMIUM_DIR}/WidevineCdm/_platform_specific/linux_x64"; \
|
||||||
unzip -p /tmp/widevine.zip LICENSE.txt > "${CHROMIUM_DIR}/WidevineCdm/LICENSE"; \
|
unzip -p /tmp/widevine.zip LICENSE.txt > "${CHROMIUM_DIR}/WidevineCdm/LICENSE"; \
|
||||||
|
@ -8,7 +8,7 @@ ARG API_URL="https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edg
|
|||||||
RUN set -eux; apt-get update; \
|
RUN set -eux; apt-get update; \
|
||||||
#
|
#
|
||||||
# fetch latest release
|
# fetch latest release
|
||||||
SRC_URL="${API_URL}$(wget -O - "${API_URL}" 2>/dev/null | sed -n 's/.*href="\([^"]*\).*/\1/p' | tail -1)"; \
|
SRC_URL="${API_URL}$(wget -O - "${API_URL}" 2>/dev/null | sed -n 's/.*href="\([^"]*\).*/\1/p' | sort --version-sort | tail -1)"; \
|
||||||
wget -O /tmp/microsoft-edge.deb "${SRC_URL}"; \
|
wget -O /tmp/microsoft-edge.deb "${SRC_URL}"; \
|
||||||
apt-get install -y --no-install-recommends openbox /tmp/microsoft-edge.deb; \
|
apt-get install -y --no-install-recommends openbox /tmp/microsoft-edge.deb; \
|
||||||
#
|
#
|
||||||
|
@ -8,7 +8,7 @@ ARG API_URL="https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edg
|
|||||||
RUN set -eux; apt-get update; \
|
RUN set -eux; apt-get update; \
|
||||||
#
|
#
|
||||||
# fetch latest release
|
# fetch latest release
|
||||||
SRC_URL="${API_URL}$(wget -O - "${API_URL}" 2>/dev/null | sed -n 's/.*href="\([^"]*\).*/\1/p' | tail -1)"; \
|
SRC_URL="${API_URL}$(wget -O - "${API_URL}" 2>/dev/null | sed -n 's/.*href="\([^"]*\).*/\1/p' | sort --version-sort | tail -1)"; \
|
||||||
wget -O /tmp/microsoft-edge.deb "${SRC_URL}"; \
|
wget -O /tmp/microsoft-edge.deb "${SRC_URL}"; \
|
||||||
apt-get install -y --no-install-recommends openbox /tmp/microsoft-edge.deb; \
|
apt-get install -y --no-install-recommends openbox /tmp/microsoft-edge.deb; \
|
||||||
#
|
#
|
||||||
|
@ -9,7 +9,7 @@ ARG LIBFFMPEG_API_URL="https://api.github.com/repos/nwjs-ffmpeg-prebuilt/nwjs-ff
|
|||||||
RUN set -eux; apt-get update; \
|
RUN set -eux; apt-get update; \
|
||||||
#
|
#
|
||||||
# fetch latest release
|
# fetch latest release
|
||||||
VERSION="$(wget -O - "${API_URL}" 2>/dev/null | sed -n 's/.*href="\([^"/]*\).*/\1/p' | tail -1)"; \
|
VERSION="$(wget -O - "${API_URL}" 2>/dev/null | sed -n 's/.*href="\([^"/]*\).*/\1/p' | sort --version-sort | tail -1)"; \
|
||||||
wget -O /tmp/opera.deb "${API_URL}${VERSION}/linux/opera-stable_${VERSION}_amd64.deb"; \
|
wget -O /tmp/opera.deb "${API_URL}${VERSION}/linux/opera-stable_${VERSION}_amd64.deb"; \
|
||||||
apt-get install -y --no-install-recommends openbox jq unzip /tmp/opera.deb; \
|
apt-get install -y --no-install-recommends openbox jq unzip /tmp/opera.deb; \
|
||||||
#
|
#
|
||||||
|
@ -21,7 +21,7 @@ RUN set -eux; apt-get update; \
|
|||||||
chmod 4755 /usr/lib/chromium/chrome-sandbox; \
|
chmod 4755 /usr/lib/chromium/chrome-sandbox; \
|
||||||
#
|
#
|
||||||
# install widevine module
|
# install widevine module
|
||||||
WIDEVINE_VERSION=$(wget --quiet -O - https://dl.google.com/widevine-cdm/versions.txt | tail -n 1); \
|
WIDEVINE_VERSION=$(wget --quiet -O - https://dl.google.com/widevine-cdm/versions.txt | sort --version-sort | tail -n 1); \
|
||||||
wget -O /tmp/widevine.zip "https://dl.google.com/widevine-cdm/${WIDEVINE_VERSION}-linux-x64.zip"; \
|
wget -O /tmp/widevine.zip "https://dl.google.com/widevine-cdm/${WIDEVINE_VERSION}-linux-x64.zip"; \
|
||||||
unzip -p /tmp/widevine.zip libwidevinecdm.so > /usr/lib/chromium/libwidevinecdm.so; \
|
unzip -p /tmp/widevine.zip libwidevinecdm.so > /usr/lib/chromium/libwidevinecdm.so; \
|
||||||
chmod 644 /usr/lib/chromium/libwidevinecdm.so; \
|
chmod 644 /usr/lib/chromium/libwidevinecdm.so; \
|
||||||
|
@ -204,7 +204,9 @@
|
|||||||
|
|
||||||
@Watch('volume', { immediate: true })
|
@Watch('volume', { immediate: true })
|
||||||
onVolume(volume: number) {
|
onVolume(volume: number) {
|
||||||
this.$accessor.video.setVolume(volume)
|
if (new URL(location.href).searchParams.has('volume')) {
|
||||||
|
this.$accessor.video.setVolume(volume)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Watch('hideControls', { immediate: true })
|
@Watch('hideControls', { immediate: true })
|
||||||
|
@ -82,6 +82,14 @@
|
|||||||
if (default_lang && this.langs.includes(default_lang)) {
|
if (default_lang && this.langs.includes(default_lang)) {
|
||||||
this.$i18n.locale = default_lang
|
this.$i18n.locale = default_lang
|
||||||
}
|
}
|
||||||
|
const show_side = new URL(location.href).searchParams.get('show_side')
|
||||||
|
if (show_side !== null) {
|
||||||
|
this.$accessor.client.setSide(show_side === '1')
|
||||||
|
}
|
||||||
|
const mute_chat = new URL(location.href).searchParams.get('mute_chat')
|
||||||
|
if (mute_chat !== null) {
|
||||||
|
this.$accessor.settings.setSound(mute_chat !== '1')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -27,6 +27,10 @@ export const mutations = mutationTree(state, {
|
|||||||
state.side = !state.side
|
state.side = !state.side
|
||||||
set('side', state.side)
|
set('side', state.side)
|
||||||
},
|
},
|
||||||
|
setSide(state, side: boolean) {
|
||||||
|
state.side = side
|
||||||
|
set('side', side)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const actions = actionTree({ state, getters, mutations }, {})
|
export const actions = actionTree({ state, getters, mutations }, {})
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* [Reverse Proxy](/getting-started/reverse-proxy)
|
* [Reverse Proxy](/getting-started/reverse-proxy)
|
||||||
* [Configuration](/getting-started/configuration)
|
* [Configuration](/getting-started/configuration)
|
||||||
* [Troubleshooting](/getting-started/troubleshooting)
|
* [Troubleshooting](/getting-started/troubleshooting)
|
||||||
|
* [Frequently Asked Questions](/getting-started/faq)
|
||||||
* [Mobile Support](/mobile-support)
|
* [Mobile Support](/mobile-support)
|
||||||
* [Contributing](/contributing)
|
* [Contributing](/contributing)
|
||||||
* [Non Goals](/non-goals)
|
* [Non Goals](/non-goals)
|
||||||
|
@ -5,9 +5,19 @@
|
|||||||
### New Features
|
### New Features
|
||||||
- Added nvidia support for firefox.
|
- Added nvidia support for firefox.
|
||||||
- Added `?lang=<lang>` parameter to the URL, which will set the language of the interface (by @mbattista).
|
- Added `?lang=<lang>` parameter to the URL, which will set the language of the interface (by @mbattista).
|
||||||
|
- Added `?show_side=1` and `?mute_chat=1` parameter to the URL, for chat mute and show side (by @mbattista).
|
||||||
|
|
||||||
|
### Bugs
|
||||||
|
- Fix incorrect version sorting for chromium, microsoft-edge, opera and ungoogledchromium.
|
||||||
|
- Fix buffer overflow in Gstreamer log function [#382](https://github.com/m1k1o/neko/pull/382) (by @@tt2468).
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
|
- Added RTMP broadcast support to nvidia docker image [#274](https://github.com/m1k1o/neko/issues/274).
|
||||||
|
- Ensured that paths are writable by neko user [#277](https://github.com/m1k1o/neko/issues/277).
|
||||||
- Git commit and tag are now included in the build when creating a docker image.
|
- Git commit and tag are now included in the build when creating a docker image.
|
||||||
|
- Remove any temporary files associated with a Form after file upload, that would be otherwise never removed.
|
||||||
|
- Add check for volume parameter in URL before setting volume (by @FapFapDragon).
|
||||||
|
- Add glib main loop to capture manager [#383](https://github.com/m1k1o/neko/pull/383) (by @tt2468).
|
||||||
|
|
||||||
## [n.eko v2.8.0](https://github.com/m1k1o/neko/releases/tag/v2.8.0)
|
## [n.eko v2.8.0](https://github.com/m1k1o/neko/releases/tag/v2.8.0)
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
## Server build dependencies
|
## Server build dependencies
|
||||||
|
|
||||||
If you want to compile goalng code locally, you must install additional dependencies in order for it to compile.
|
If you want to compile Golang code locally, you must install additional dependencies in order for it to compile.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
apt-get install -y --no-install-recommends libx11-dev libxrandr-dev libxtst-dev libgstreamer1.0-dev
|
apt-get install -y --no-install-recommends libx11-dev libxrandr-dev libxtst-dev libgstreamer1.0-dev
|
||||||
|
@ -87,7 +87,48 @@ GHCR images are built using GitHub actions for every tag.
|
|||||||
### Networking:
|
### Networking:
|
||||||
- If you want to use n.eko in **external** network, you can omit `NEKO_NAT1TO1`. It will automatically get your Public IP.
|
- If you want to use n.eko in **external** network, you can omit `NEKO_NAT1TO1`. It will automatically get your Public IP.
|
||||||
- If you want to use n.eko in **internal** network, set `NEKO_NAT1TO1` to your local IP address (e.g. `NEKO_NAT1TO1: 192.168.1.20`)-
|
- If you want to use n.eko in **internal** network, set `NEKO_NAT1TO1` to your local IP address (e.g. `NEKO_NAT1TO1: 192.168.1.20`)-
|
||||||
- Currently, it is not supported to supply multiple NAT addresses (see https://github.com/m1k1o/neko/issues/47).
|
|
||||||
|
Currently, it is not supported to supply multiple NAT addresses directly to neko (see https://github.com/m1k1o/neko/issues/47).
|
||||||
|
|
||||||
|
But it can be acheived by deploying own turn server alongside neko that is accessible from your LAN:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.4"
|
||||||
|
services:
|
||||||
|
neko:
|
||||||
|
image: "m1k1o/neko:firefox"
|
||||||
|
restart: "unless-stopped"
|
||||||
|
shm_size: "2gb"
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
- "52000-52100:52000-52100/udp"
|
||||||
|
environment:
|
||||||
|
NEKO_SCREEN: 1920x1080@30
|
||||||
|
NEKO_PASSWORD: neko
|
||||||
|
NEKO_PASSWORD_ADMIN: admin
|
||||||
|
NEKO_EPR: 52000-52100
|
||||||
|
NEKO_ICESERVERS: '[{ "urls": [ "turn:192.168.1.60:3478" ], "username":"neko", "credential":"neko" }, { "urls": [ "stun:stun.nextcloud.com:3478" ] }]'
|
||||||
|
coturn:
|
||||||
|
image: 'coturn/coturn:latest'
|
||||||
|
network_mode: "host"
|
||||||
|
command: |
|
||||||
|
-n
|
||||||
|
--realm=localhost
|
||||||
|
--fingerprint
|
||||||
|
--listening-ip=0.0.0.0
|
||||||
|
--external-ip=192.168.1.60
|
||||||
|
--listening-port=3478
|
||||||
|
--min-port=49160
|
||||||
|
--max-port=49200
|
||||||
|
--log-file=stdout
|
||||||
|
--user=neko:neko
|
||||||
|
--lt-cred-mech
|
||||||
|
```
|
||||||
|
|
||||||
|
- Replace `192.168.1.60` with your LAN IP address, and allow ports `49160-49200/udp` and `3478/tcp` in your LAN.
|
||||||
|
- Make sure you don't use `NEKO_ICELITE: true` because ICE LITE does not support TURN servers.
|
||||||
|
|
||||||
|
This setup adds local turn server to neko. It won't be reachable by your remote clients and your own IP won't be reachable from your lan. So it effectively just adds local candidate and allows connections from LAN.
|
||||||
|
|
||||||
### Why so many ports?
|
### Why so many ports?
|
||||||
- WebRTC needs UDP ports in order to transfer Audio/Video towards user and Mouse/Keyboard events to the server in real time.
|
- WebRTC needs UDP ports in order to transfer Audio/Video towards user and Mouse/Keyboard events to the server in real time.
|
||||||
@ -176,7 +217,7 @@ NEKO_ICESERVERS: '[{"urls": ["turn:<MY-COTURN-SERVER>:443?transport=udp", "turn:
|
|||||||
|
|
||||||
### Nvidia GPU acceleration
|
### Nvidia GPU acceleration
|
||||||
|
|
||||||
You need to have [nvidia-docker](https://github.com/NVIDIA/nvidia-docker) installed, start the container with `--gpus all` flag and use images built for nvidia (see above).
|
You need to have [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-container-toolkit) installed, start the container with `--gpus all` flag and use images built for nvidia (see above).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d --gpus all \
|
docker run -d --gpus all \
|
||||||
@ -257,6 +298,8 @@ NEKO_BROADCAST_PIPELINE: "flvmux name=mux ! rtmpsink location={url} pulsesrc dev
|
|||||||
- Adding `?embed=1` will hide most additional components and show only video.
|
- Adding `?embed=1` will hide most additional components and show only video.
|
||||||
- Adding `?volume=<0-1>` will set volume to given value.
|
- Adding `?volume=<0-1>` will set volume to given value.
|
||||||
- Adding `?lang=<language>` will set language to given value.
|
- Adding `?lang=<language>` will set language to given value.
|
||||||
|
- Adding `?show_side=1` will show the sidebar on startup.
|
||||||
|
- Adding `?mute_chat=1` will mute the chat on startup.
|
||||||
- e.g. `http(s)://<URL:Port>/?pwd=neko&usr=guest&cast=1`
|
- e.g. `http(s)://<URL:Port>/?pwd=neko&usr=guest&cast=1`
|
||||||
|
|
||||||
### Screen size
|
### Screen size
|
||||||
|
57
docs/getting-started/faq.md
Normal file
57
docs/getting-started/faq.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Frequently Asked Questions
|
||||||
|
|
||||||
|
## How to enable debug mode?
|
||||||
|
|
||||||
|
To see verbose information from n.eko server, you can enable debug mode using `NEKO_DEBUG`.
|
||||||
|
|
||||||
|
```diff
|
||||||
|
version: "3.4"
|
||||||
|
services:
|
||||||
|
neko:
|
||||||
|
image: "m1k1o/neko:firefox"
|
||||||
|
restart: "unless-stopped"
|
||||||
|
shm_size: "2gb"
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
- "52000-52100:52000-52100/udp"
|
||||||
|
environment:
|
||||||
|
NEKO_SCREEN: 1920x1080@30
|
||||||
|
NEKO_PASSWORD: neko
|
||||||
|
NEKO_PASSWORD_ADMIN: admin
|
||||||
|
NEKO_EPR: 52000-52100
|
||||||
|
NEKO_ICELITE: 1
|
||||||
|
+ NEKO_DEBUG: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensure, that you have enabled debug mode in javascript console too, in order to see verbose information from client.
|
||||||
|
|
||||||
|
## Chinese input method is not working
|
||||||
|
|
||||||
|
There exists an extension for Chrome that allows you to use Chinese input method. You can install it from [here](https://chrome.google.com/webstore/detail/mclkkofklkfljcocdinagocijmpgbhab). Alternatively, you can use Google Input Tools from [here](https://www.google.com/inputtools/chrome/).
|
||||||
|
|
||||||
|
## Only black screen is displayed but remote cursor is moving for Chromium-based browsers (Chrome, Edge, etc.)
|
||||||
|
|
||||||
|
Check if you did not forget to add cap_add to your docker-compose file.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
cap_add:
|
||||||
|
- SYS_ADMIN
|
||||||
|
```
|
||||||
|
|
||||||
|
## How can I embed the Neko desktop into web page without login prompt coming up for viewers?
|
||||||
|
|
||||||
|
You can use the following URL to embed the Neko desktop into a web page without login prompt coming up for viewers:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://<your-neko-server-ip>:8080/?usr=neko&pwd=neko
|
||||||
|
```
|
||||||
|
|
||||||
|
https://stackoverflow.com/questions/15276929/how-to-make-a-video-fullscreen-when-it-is-placed-inside-an-iframe
|
||||||
|
|
||||||
|
Your iframe needs an attribute: `allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true"` or more modern `allow="fullscreen *"`. For the second you can remove the star if your iframe has the same origin or replace it with your iframe origin.
|
||||||
|
|
||||||
|
## Can I use neko without docker?
|
||||||
|
|
||||||
|
It is strongly recommended to use Neko with Docker, as it is the easiest way to run it. But you should be able to install Neko "natively" on your host system. Neko is based on Debian and uses Xorg and Pulseaudio. You would just need to follow steps that are in Dockerfile, install all dependencies on your host system and then just run it.
|
||||||
|
|
||||||
|
However, it is recommend to start with existing system that has GUI with desktop manager, is based on Xorg and uses Pulseaudio (e.g. Ubuntu Desktop 22.04). For that matter you only need to install gstreamer dependencies, configure pulseaudio properly and run neko binary (you don't need to build it from scratch, you can copy it from docker image).
|
@ -94,7 +94,7 @@ services:
|
|||||||
+ NEKO_IPFETCH: https://ifconfig.co/ip
|
+ NEKO_IPFETCH: https://ifconfig.co/ip
|
||||||
```
|
```
|
||||||
|
|
||||||
Or you can specify your IP address manually using `NEKO_NAT1TO1`:
|
Or you can specify your IP address manually using `NEKO_NAT1TO1`: (It's read as NAT 1 to 1, so it's capital letter 'O', not zero '0', in NAT1`TO`1)
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
version: "3.4"
|
version: "3.4"
|
||||||
@ -129,6 +129,7 @@ Example for pfsense with truecharts docker container:
|
|||||||
- Test externally to confirm it works.
|
- Test externally to confirm it works.
|
||||||
- Internally you have to access it using `<your-public-ip>:port`
|
- Internally you have to access it using `<your-public-ip>:port`
|
||||||
|
|
||||||
|
If your router does not support NAT Loopback (NAT Hairpinning), you can use turn servers to overcome this issue. See [more details here](https://neko.m1k1o.net/#/getting-started/?id=networking) on how to setup local coturn instance.
|
||||||
|
|
||||||
### Neko works locally, but not externally
|
### Neko works locally, but not externally
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
static void gstreamer_pipeline_log(GstPipelineCtx *ctx, char* level, const char* format, ...) {
|
static void gstreamer_pipeline_log(GstPipelineCtx *ctx, char* level, const char* format, ...) {
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
va_start(argptr, format);
|
va_start(argptr, format);
|
||||||
char buffer[100];
|
char buffer[4096];
|
||||||
vsprintf(buffer, format, argptr);
|
vsnprintf(buffer, sizeof(buffer), format, argptr);
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
goPipelineLog(level, buffer, ctx->pipelineId);
|
goPipelineLog(level, buffer, ctx->pipelineId);
|
||||||
}
|
}
|
||||||
|
@ -31,12 +31,29 @@ var pSerial int32
|
|||||||
var pipelines = make(map[int]*Pipeline)
|
var pipelines = make(map[int]*Pipeline)
|
||||||
var pipelinesLock sync.Mutex
|
var pipelinesLock sync.Mutex
|
||||||
var registry *C.GstRegistry
|
var registry *C.GstRegistry
|
||||||
|
var gMainLoop *C.GMainLoop
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
C.gst_init(nil, nil)
|
C.gst_init(nil, nil)
|
||||||
registry = C.gst_registry_get()
|
registry = C.gst_registry_get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunMainLoop() {
|
||||||
|
if gMainLoop != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gMainLoop = C.g_main_loop_new(nil, C.int(0))
|
||||||
|
C.g_main_loop_run(gMainLoop)
|
||||||
|
}
|
||||||
|
|
||||||
|
func QuitMainLoop() {
|
||||||
|
if gMainLoop == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
C.g_main_loop_quit(gMainLoop)
|
||||||
|
gMainLoop = nil
|
||||||
|
}
|
||||||
|
|
||||||
func CreatePipeline(pipelineStr string) (*Pipeline, error) {
|
func CreatePipeline(pipelineStr string) (*Pipeline, error) {
|
||||||
id := atomic.AddInt32(&pSerial, 1)
|
id := atomic.AddInt32(&pSerial, 1)
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"m1k1o/neko/internal/capture/gst"
|
||||||
"m1k1o/neko/internal/config"
|
"m1k1o/neko/internal/config"
|
||||||
"m1k1o/neko/internal/types"
|
"m1k1o/neko/internal/types"
|
||||||
)
|
)
|
||||||
@ -53,6 +54,7 @@ func (manager *CaptureManagerCtx) Start() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go gst.RunMainLoop()
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
before, ok := <-manager.desktop.GetScreenSizeChangeChannel()
|
before, ok := <-manager.desktop.GetScreenSizeChangeChannel()
|
||||||
@ -100,6 +102,8 @@ func (manager *CaptureManagerCtx) Shutdown() error {
|
|||||||
manager.audio.shutdown()
|
manager.audio.shutdown()
|
||||||
manager.video.shutdown()
|
manager.video.shutdown()
|
||||||
|
|
||||||
|
gst.QuitMainLoop()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ type Server struct {
|
|||||||
Cert string
|
Cert string
|
||||||
Key string
|
Key string
|
||||||
Bind string
|
Bind string
|
||||||
|
Proxy bool
|
||||||
Static string
|
Static string
|
||||||
PathPrefix string
|
PathPrefix string
|
||||||
CORS []string
|
CORS []string
|
||||||
@ -35,6 +36,11 @@ func (Server) Init(cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Bool("proxy", false, "enable reverse proxy mode")
|
||||||
|
if err := viper.BindPFlag("proxy", cmd.PersistentFlags().Lookup("proxy")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
cmd.PersistentFlags().String("static", "./www", "path to neko client files to serve")
|
cmd.PersistentFlags().String("static", "./www", "path to neko client files to serve")
|
||||||
if err := viper.BindPFlag("static", cmd.PersistentFlags().Lookup("static")); err != nil {
|
if err := viper.BindPFlag("static", cmd.PersistentFlags().Lookup("static")); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -57,6 +63,7 @@ func (s *Server) Set() {
|
|||||||
s.Cert = viper.GetString("cert")
|
s.Cert = viper.GetString("cert")
|
||||||
s.Key = viper.GetString("key")
|
s.Key = viper.GetString("key")
|
||||||
s.Bind = viper.GetString("bind")
|
s.Bind = viper.GetString("bind")
|
||||||
|
s.Proxy = viper.GetBool("proxy")
|
||||||
s.Static = viper.GetString("static")
|
s.Static = viper.GetString("static")
|
||||||
s.PathPrefix = path.Join("/", path.Clean(viper.GetString("path_prefix")))
|
s.PathPrefix = path.Join("/", path.Clean(viper.GetString("path_prefix")))
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
type WebSocket struct {
|
type WebSocket struct {
|
||||||
Password string
|
Password string
|
||||||
AdminPassword string
|
AdminPassword string
|
||||||
Proxy bool
|
|
||||||
Locks []string
|
Locks []string
|
||||||
|
|
||||||
ControlProtection bool
|
ControlProtection bool
|
||||||
@ -30,11 +29,6 @@ func (WebSocket) Init(cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.PersistentFlags().Bool("proxy", false, "enable reverse proxy mode")
|
|
||||||
if err := viper.BindPFlag("proxy", cmd.PersistentFlags().Lookup("proxy")); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.PersistentFlags().StringSlice("locks", []string{}, "resources, that will be locked when starting (control, login)")
|
cmd.PersistentFlags().StringSlice("locks", []string{}, "resources, that will be locked when starting (control, login)")
|
||||||
if err := viper.BindPFlag("locks", cmd.PersistentFlags().Lookup("locks")); err != nil {
|
if err := viper.BindPFlag("locks", cmd.PersistentFlags().Lookup("locks")); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -63,7 +57,6 @@ func (WebSocket) Init(cmd *cobra.Command) error {
|
|||||||
func (s *WebSocket) Set() {
|
func (s *WebSocket) Set() {
|
||||||
s.Password = viper.GetString("password")
|
s.Password = viper.GetString("password")
|
||||||
s.AdminPassword = viper.GetString("password_admin")
|
s.AdminPassword = viper.GetString("password_admin")
|
||||||
s.Proxy = viper.GetBool("proxy")
|
|
||||||
s.Locks = viper.GetStringSlice("locks")
|
s.Locks = viper.GetStringSlice("locks")
|
||||||
|
|
||||||
s.ControlProtection = viper.GetBool("control_protection")
|
s.ControlProtection = viper.GetBool("control_protection")
|
||||||
|
@ -35,6 +35,9 @@ func New(conf *config.Server, webSocketHandler types.WebSocketHandler, desktop t
|
|||||||
|
|
||||||
router := chi.NewRouter()
|
router := chi.NewRouter()
|
||||||
router.Use(middleware.RequestID) // Create a request ID for each request
|
router.Use(middleware.RequestID) // Create a request ID for each request
|
||||||
|
if conf.Proxy {
|
||||||
|
router.Use(middleware.RealIP)
|
||||||
|
}
|
||||||
router.Use(middleware.RequestLogger(&logformatter{logger}))
|
router.Use(middleware.RequestLogger(&logformatter{logger}))
|
||||||
router.Use(middleware.Recoverer) // Recover from panics without crashing server
|
router.Use(middleware.Recoverer) // Recover from panics without crashing server
|
||||||
router.Use(middleware.Compress(5, "application/octet-stream"))
|
router.Use(middleware.Compress(5, "application/octet-stream"))
|
||||||
@ -163,7 +166,13 @@ func New(conf *config.Server, webSocketHandler types.WebSocketHandler, desktop t
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r.ParseMultipartForm(32 << 20)
|
err = r.ParseMultipartForm(32 << 20)
|
||||||
|
if err != nil || r.MultipartForm == nil {
|
||||||
|
logger.Warn().Err(err).Msg("failed to parse multipart form")
|
||||||
|
http.Error(w, "error parsing form", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, formheader := range r.MultipartForm.File["files"] {
|
for _, formheader := range r.MultipartForm.File["files"] {
|
||||||
filePath := webSocketHandler.FileTransferPath(formheader.Filename)
|
filePath := webSocketHandler.FileTransferPath(formheader.Filename)
|
||||||
|
|
||||||
@ -184,6 +193,11 @@ func New(conf *config.Server, webSocketHandler types.WebSocketHandler, desktop t
|
|||||||
|
|
||||||
io.Copy(f, formfile)
|
io.Copy(f, formfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = r.MultipartForm.RemoveAll()
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn().Err(err).Msg("failed to remove multipart form")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,14 +38,3 @@ func GetIP(serverUrl string) (string, error) {
|
|||||||
|
|
||||||
return string(bytes.TrimSpace(buf)), nil
|
return string(bytes.TrimSpace(buf)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetHttpRequestIP(r *http.Request, proxy bool) string {
|
|
||||||
IPAddress := r.Header.Get("X-Real-Ip")
|
|
||||||
if IPAddress == "" {
|
|
||||||
IPAddress = r.Header.Get("X-Forwarded-For")
|
|
||||||
}
|
|
||||||
if IPAddress == "" || !proxy {
|
|
||||||
IPAddress = r.RemoteAddr
|
|
||||||
}
|
|
||||||
return IPAddress
|
|
||||||
}
|
|
||||||
|
@ -290,7 +290,7 @@ func (ws *WebSocketHandler) Upgrade(w http.ResponseWriter, r *http.Request) erro
|
|||||||
socket := &WebSocket{
|
socket := &WebSocket{
|
||||||
id: id,
|
id: id,
|
||||||
ws: ws,
|
ws: ws,
|
||||||
address: utils.GetHttpRequestIP(r, ws.conf.Proxy),
|
address: r.RemoteAddr,
|
||||||
connection: connection,
|
connection: connection,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user