27 Commits

Author SHA1 Message Date
75c31ab5bc login screen position fixed, #381. 2024-04-15 18:04:17 +02:00
bb595e8f1f Merge branch 'master' into scroll-to-chat-on-mobile 2024-04-04 23:58:33 +02:00
5f698330fc hide controls on mobile when locked. #381 2024-04-04 23:55:13 +02:00
f32fc989b9 overlay: no pointer events when not hosting. #381 2024-04-04 23:48:59 +02:00
8f8403ca59 update screen size to 1024px. 2024-04-02 23:55:45 +02:00
1d5e159b74 WIP: scroll to chat proof of concept on mobile, #381. 2024-04-02 23:50:38 +02:00
d1f1be4e86 add to docs faq: Run neko without docker on host #314. 2024-03-28 23:54:26 +01:00
e754e66878 added Frequently Asked Questions to docs. 2024-03-28 23:47:20 +01:00
26af1dc7f5 add Nat Hairpinning deployment to docs #378. 2024-03-28 23:31:22 +01:00
0c9055e4f6 update docs, nvidia docker is replaced by NVIDIA Container Toolkit. 2024-03-28 23:30:34 +01:00
c200326512 update changelog. 2024-03-28 22:57:54 +01:00
b1ce755210 Add glib main loop to capture manager (#383)
The gstreamer documentation is not particularly amazing on whether or
not this is necessary, but it's clear that some gstreamer events will
not be delivered to their handlers without a running glib loop. This
runs one loop for all pipelines, which should be more than enough.

Disclaimer: This may conflict in demodesk/neko with the dragdrop
feature. Anyone backporting this bug fix to that repo should
investigate whether the loop created by `gtk_main()` will conflict with
this one before blindly porting.

Fixes #380
Fixes #284
2024-03-27 21:35:04 +01:00
2b13220d63 Fix buffer overflow in Gstreamer log function (#382)
vsprintf() is dangerous, and can overflow easily, especially with small
buffers like the 100 byte one that was being used. This changes the
buffer size to a more sane 4KiB, and uses vsnprintf() to automatically
concatenate a large log message instead of overflowing and crashing.
2024-03-27 21:32:47 +01:00
db6f9c957e add check for volume parameter in URL before setting volume (#372) 2024-03-10 13:43:30 +01:00
798bf579c0 fix typo (#367) 2024-02-09 23:49:11 +01:00
2f9964580f use 1 instead of true for consistency. 2024-01-06 17:33:39 +01:00
b8881b3a46 added doc 2024-01-06 15:05:20 +01:00
355c0eac0d add parameter for chat mute and show side 2024-01-06 15:02:13 +01:00
4d023df692 update docs to explicitly differentiate between letter O and zero (#354) 2024-01-04 17:18:36 +01:00
792b1ac111 remove any temporary files associated with a Form, fixes #347. 2023-12-26 15:49:16 +01:00
a03b29ba01 add version sort to get the latest version, fixes #348. 2023-12-26 15:43:50 +01:00
683b750189 move proxy option to server. 2023-11-19 14:50:23 +01:00
3c4d7b9d60 upgrade go-chi to v5. 2023-10-15 13:18:43 +02:00
7a9b33706a chore: remove refs to deprecated io/ioutil (#329) 2023-08-31 13:32:16 +02:00
052a961fd9 fix docs #327, 2023-08-26 21:13:20 +01:00
8ef9c1aff5 add firefox nvidia image to docs. 2023-06-26 17:39:34 +02:00
6ed3493aa0 update LICENCE. 2023-05-11 00:42:12 +02:00
30 changed files with 222 additions and 60 deletions

View File

@ -10,7 +10,7 @@ RUN set -eux; \
#
# install widevine module
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"; \
mkdir -p "${CHROMIUM_DIR}/WidevineCdm/_platform_specific/linux_x64"; \
unzip -p /tmp/widevine.zip LICENSE.txt > "${CHROMIUM_DIR}/WidevineCdm/LICENSE"; \

View File

@ -14,7 +14,7 @@ RUN set -eux; \
#
# install widevine module
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"; \
mkdir -p "${CHROMIUM_DIR}/WidevineCdm/_platform_specific/linux_x64"; \
unzip -p /tmp/widevine.zip LICENSE.txt > "${CHROMIUM_DIR}/WidevineCdm/LICENSE"; \

View File

@ -8,7 +8,7 @@ ARG API_URL="https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edg
RUN set -eux; apt-get update; \
#
# 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}"; \
apt-get install -y --no-install-recommends openbox /tmp/microsoft-edge.deb; \
#

View File

@ -8,7 +8,7 @@ ARG API_URL="https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edg
RUN set -eux; apt-get update; \
#
# 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}"; \
apt-get install -y --no-install-recommends openbox /tmp/microsoft-edge.deb; \
#

View File

@ -9,7 +9,7 @@ ARG LIBFFMPEG_API_URL="https://api.github.com/repos/nwjs-ffmpeg-prebuilt/nwjs-ff
RUN set -eux; apt-get update; \
#
# 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"; \
apt-get install -y --no-install-recommends openbox jq unzip /tmp/opera.deb; \
#

View File

@ -21,7 +21,7 @@ RUN set -eux; apt-get update; \
chmod 4755 /usr/lib/chromium/chrome-sandbox; \
#
# 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"; \
unzip -p /tmp/widevine.zip libwidevinecdm.so > /usr/lib/chromium/libwidevinecdm.so; \
chmod 644 /usr/lib/chromium/libwidevinecdm.so; \

View File

@ -186,7 +186,9 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 Nurdism <nurdism.io@gmail.com>, 2020-2021 m1k1o
Copyright (C) 2020 Nurdism <nurdism.io@gmail.com>
Copyright (C) 2020-2023 m1k1o
All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -119,23 +119,30 @@
}
}
@media only screen and (max-width: 600px) {
#neko.expanded {
.neko-main {
transform: translateX(calc(-100% + 65px));
@media only screen and (max-width: 1024px) {
html,
body {
overflow-y: auto !important;
width: auto !important;
height: auto !important;
}
video {
display: none;
}
body > p {
display: none;
}
#neko {
position: relative;
flex-direction: column;
max-height: initial !important;
.neko-main .video-container {
height: 100vh;
}
.neko-menu {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 65px;
width: calc(100% - 65px);
height: 100vh;
width: 100% !important;
}
}
}
@ -204,7 +211,9 @@
@Watch('volume', { immediate: true })
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 })

View File

@ -24,7 +24,7 @@
<style lang="scss" scoped>
.connect {
position: absolute;
position: fixed;
top: 0;
left: 0;
right: 0;

View File

@ -82,6 +82,14 @@
if (default_lang && this.langs.includes(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>

View File

@ -13,6 +13,7 @@
class="overlay"
tabindex="0"
data-gramm="false"
:style="{ pointerEvents: hosting ? 'auto' : 'none' }"
@click.stop.prevent
@contextmenu.stop.prevent
@wheel.stop.prevent="onWheel"
@ -36,7 +37,7 @@
<ul v-if="!fullscreen && !hideControls" class="video-menu top">
<li><i @click.stop.prevent="requestFullscreen" class="fas fa-expand"></i></li>
<li v-if="admin"><i @click.stop.prevent="openResolution" class="fas fa-desktop"></i></li>
<li v-if="!implicitHosting" :class="extraControls || 'extra-control'">
<li v-if="!controlLocked && !implicitHosting" :class="extraControls || 'extra-control'">
<i
:class="[hosted && !hosting ? 'disabled' : '', !hosted && !hosting ? 'faded' : '', 'fas', 'fa-keyboard']"
@click.stop.prevent="toggleControl"

View File

@ -27,6 +27,10 @@ export const mutations = mutationTree(state, {
state.side = !state.side
set('side', state.side)
},
setSide(state, side: boolean) {
state.side = side
set('side', side)
},
})
export const actions = actionTree({ state, getters, mutations }, {})

View File

@ -6,6 +6,7 @@
* [Reverse Proxy](/getting-started/reverse-proxy)
* [Configuration](/getting-started/configuration)
* [Troubleshooting](/getting-started/troubleshooting)
* [Frequently Asked Questions](/getting-started/faq)
* [Mobile Support](/mobile-support)
* [Contributing](/contributing)
* [Non Goals](/non-goals)

View File

@ -5,9 +5,19 @@
### New Features
- Added nvidia support for firefox.
- 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
- 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.
- 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)

View File

@ -10,7 +10,7 @@
## 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
apt-get install -y --no-install-recommends libx11-dev libxrandr-dev libxtst-dev libgstreamer1.0-dev

View File

@ -50,7 +50,7 @@ All images are also available on [GitHub Container Registry](https://github.com/
- `ghcr.io/m1k1o/neko/xfce:latest`
- `ghcr.io/m1k1o/neko/kde:latest`
For ARM-based images (like Raspberry Pi - with GPU hardware acceleration, Oracle Cloud ARM tier). Currently, not all images are available for ARM, because not all applications are available for ARM.
For ARM-based images (like Raspberry Pi - with GPU hardware acceleration, Oracle Cloud ARM tier). Currently, not all images are available for ARM, because not all applications are available for ARM. Please note, that `m1k1o/neko:arm-*` images from dockerhub are currently not maintained and they can contain outdated software. Please use images below:
- `ghcr.io/m1k1o/neko/arm-firefox:latest`
- `ghcr.io/m1k1o/neko/arm-chromium:latest`
@ -74,8 +74,9 @@ For images with VAAPI GPU hardware acceleration using intel drivers use:
- `ghcr.io/m1k1o/neko/intel-xfce:latest`
- `ghcr.io/m1k1o/neko/intel-kde:latest`
For images with Nvidia GPU hardware acceleration using EGL (see example below) use:
For images with Nvidia GPU hardware acceleration using EGL (see example below) use (please note, there is a known issue with EGL and Chromium-based browsers, see [here](https://github.com/m1k1o/neko/issues/279)):
- `ghcr.io/m1k1o/neko/nvidia-firefox:latest`
- `ghcr.io/m1k1o/neko/nvidia-chromium:latest`
- `ghcr.io/m1k1o/neko/nvidia-google-chrome:latest`
- `ghcr.io/m1k1o/neko/nvidia-microsoft-edge:latest`
@ -86,7 +87,48 @@ GHCR images are built using GitHub actions for every tag.
### 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 **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?
- WebRTC needs UDP ports in order to transfer Audio/Video towards user and Mouse/Keyboard events to the server in real time.
@ -175,7 +217,7 @@ NEKO_ICESERVERS: '[{"urls": ["turn:<MY-COTURN-SERVER>:443?transport=udp", "turn:
### 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
docker run -d --gpus all \
@ -256,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 `?volume=<0-1>` will set volume 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`
### Screen size

View File

@ -72,7 +72,8 @@ services:
version: "3.4"
services:
neko:
image: "m1k1o/neko:arm-chromium"
# see docs for more variants
image: "ghcr.io/m1k1o/neko/arm-chromium:latest"
restart: "unless-stopped"
# increase on rpi's with more then 1gb ram.
shm_size: "520mb"

View 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).

View File

@ -94,7 +94,7 @@ services:
+ 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
version: "3.4"
@ -129,6 +129,7 @@ Example for pfsense with truecharts docker container:
- Test externally to confirm it works.
- 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

View File

@ -4,7 +4,7 @@ go 1.20
require (
github.com/fsnotify/fsnotify v1.6.0
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/chi/v5 v5.0.10
github.com/go-chi/cors v1.2.1
github.com/gorilla/websocket v1.5.0
github.com/pion/ice/v2 v2.3.0

View File

@ -63,8 +63,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=

View File

@ -3,8 +3,8 @@
static void gstreamer_pipeline_log(GstPipelineCtx *ctx, char* level, const char* format, ...) {
va_list argptr;
va_start(argptr, format);
char buffer[100];
vsprintf(buffer, format, argptr);
char buffer[4096];
vsnprintf(buffer, sizeof(buffer), format, argptr);
va_end(argptr);
goPipelineLog(level, buffer, ctx->pipelineId);
}

View File

@ -31,12 +31,29 @@ var pSerial int32
var pipelines = make(map[int]*Pipeline)
var pipelinesLock sync.Mutex
var registry *C.GstRegistry
var gMainLoop *C.GMainLoop
func init() {
C.gst_init(nil, nil)
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) {
id := atomic.AddInt32(&pSerial, 1)

View File

@ -6,6 +6,7 @@ import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"m1k1o/neko/internal/capture/gst"
"m1k1o/neko/internal/config"
"m1k1o/neko/internal/types"
)
@ -53,6 +54,7 @@ func (manager *CaptureManagerCtx) Start() {
}
}
go gst.RunMainLoop()
go func() {
for {
before, ok := <-manager.desktop.GetScreenSizeChangeChannel()
@ -100,6 +102,8 @@ func (manager *CaptureManagerCtx) Shutdown() error {
manager.audio.shutdown()
manager.video.shutdown()
gst.QuitMainLoop()
return nil
}

View File

@ -14,6 +14,7 @@ type Server struct {
Cert string
Key string
Bind string
Proxy bool
Static string
PathPrefix string
CORS []string
@ -35,6 +36,11 @@ func (Server) Init(cmd *cobra.Command) error {
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")
if err := viper.BindPFlag("static", cmd.PersistentFlags().Lookup("static")); err != nil {
return err
@ -57,6 +63,7 @@ func (s *Server) Set() {
s.Cert = viper.GetString("cert")
s.Key = viper.GetString("key")
s.Bind = viper.GetString("bind")
s.Proxy = viper.GetBool("proxy")
s.Static = viper.GetString("static")
s.PathPrefix = path.Join("/", path.Clean(viper.GetString("path_prefix")))

View File

@ -10,7 +10,6 @@ import (
type WebSocket struct {
Password string
AdminPassword string
Proxy bool
Locks []string
ControlProtection bool
@ -30,11 +29,6 @@ func (WebSocket) Init(cmd *cobra.Command) error {
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)")
if err := viper.BindPFlag("locks", cmd.PersistentFlags().Lookup("locks")); err != nil {
return err
@ -63,7 +57,6 @@ func (WebSocket) Init(cmd *cobra.Command) error {
func (s *WebSocket) Set() {
s.Password = viper.GetString("password")
s.AdminPassword = viper.GetString("password_admin")
s.Proxy = viper.GetBool("proxy")
s.Locks = viper.GetStringSlice("locks")
s.ControlProtection = viper.GetBool("control_protection")

View File

@ -11,8 +11,8 @@ import (
"regexp"
"strconv"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
@ -35,6 +35,9 @@ func New(conf *config.Server, webSocketHandler types.WebSocketHandler, desktop t
router := chi.NewRouter()
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.Recoverer) // Recover from panics without crashing server
router.Use(middleware.Compress(5, "application/octet-stream"))
@ -163,7 +166,13 @@ func New(conf *config.Server, webSocketHandler types.WebSocketHandler, desktop t
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"] {
filePath := webSocketHandler.FileTransferPath(formheader.Filename)
@ -184,6 +193,11 @@ func New(conf *config.Server, webSocketHandler types.WebSocketHandler, desktop t
io.Copy(f, formfile)
}
err = r.MultipartForm.RemoveAll()
if err != nil {
logger.Warn().Err(err).Msg("failed to remove multipart form")
}
})
}

View File

@ -5,7 +5,7 @@ import (
"net/http"
"time"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/chi/v5/middleware"
"github.com/rs/zerolog"
)

View File

@ -2,7 +2,7 @@ package utils
import (
"bytes"
"io/ioutil"
"io"
"net"
"net/http"
"time"
@ -31,21 +31,10 @@ func GetIP(serverUrl string) (string, error) {
}
defer rsp.Body.Close()
buf, err := ioutil.ReadAll(rsp.Body)
buf, err := io.ReadAll(rsp.Body)
if err != nil {
return "", err
}
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
}

View File

@ -290,7 +290,7 @@ func (ws *WebSocketHandler) Upgrade(w http.ResponseWriter, r *http.Request) erro
socket := &WebSocket{
id: id,
ws: ws,
address: utils.GetHttpRequestIP(r, ws.conf.Proxy),
address: r.RemoteAddr,
connection: connection,
}