Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
8c8e630
新增配置文件以定义允许的权限
Viyyy May 22, 2026
d970c83
新增开发指南文档,涵盖项目概述、结构、技术栈及构建命令
Viyyy May 22, 2026
59f30f9
新增忽略 data 目录中的所有文件
Viyyy May 22, 2026
a7f7295
feat: 添加开发用 Dockerfile,配置 USTC 镜像源和 neko 服务参数
Viyyy May 22, 2026
457a076
feat: 放开 Chrome 下载限制和剪贴板权限,移除 --disable-file-system 标志
Viyyy May 22, 2026
dde0db1
feat: 文件管理 API 支持重命名和删除,legacy handler 新增对应代理路由
Viyyy May 22, 2026
583ffdc
feat: 新增剪贴板图片上传接口,开放用户剪贴板访问权限
Viyyy May 22, 2026
23de851
feat: Ctrl+V 粘贴图片/文件自动上传到容器下载目录,文件名含类型前缀和时间戳,修复 DataChannel 未就绪时发送报错
Viyyy May 22, 2026
bcf5831
feat: 文件面板新增按类型筛选、图片/视频/音频/PDF/文本预览、重命名和删除功能
Viyyy May 22, 2026
100efe0
feat: 分辨率菜单支持自定义宽高帧率输入,新增适应当前窗口大小选项
Viyyy May 22, 2026
fa17998
feat: 网页全屏模式(隐藏 header/控制栏/侧边栏),控制栏可折叠,分辨率设置持久化到 localStorage
Viyyy May 22, 2026
698489d
feat: 新增 Git 相关 Bash 权限,支持 git add 和 git commit 操作
Viyyy May 22, 2026
07bf364
feat: add CUDA-accelerated Dockerfile and compose for NVIDIA GPU support
Viyyy May 22, 2026
7d09a6e
feat: extract env vars to .env.example, both compose files now use en…
Viyyy May 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"permissions": {
"allow": [
"Skill(update-config)",
"Skill(update-config:*)",
"WebSearch",
"Bash(docker pull *)",
"Bash(docker build *)",
"Bash(docker run *)",
"Bash(docker rm *)",
"Bash(curl -s http://localhost:8080/api/stats)",
"Bash(docker exec *)",
"Bash(ipconfig)",
"Bash(docker compose *)",
"Bash(git add *)",
"Bash(git commit *)"
]
Comment on lines +3 to +17
}
}
194 changes: 194 additions & 0 deletions .claude/skills/dev-guide/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
---
name: dev-guide
description: Development guide for the neko project. Use when asked to add features, fix bugs, or make changes to the server (Go) or client (Vue 2) codebase. Covers architecture, conventions, build commands, and common patterns.
---

# Neko Development Guide

## Project Overview

Neko is a self-hosted virtual browser/desktop sharing system. It streams a Docker container's X11 desktop to multiple users via WebRTC, with bidirectional mouse/keyboard control through WebRTC DataChannels.

## Repository Structure

```
neko/
├── server/ # Go backend
│ ├── cmd/ # CLI entrypoints (cobra)
│ ├── internal/ # Private packages
│ │ ├── api/ # HTTP REST API (chi router)
│ │ ├── capture/ # GStreamer screen capture
│ │ ├── desktop/ # X11/Xorg input injection
│ │ ├── http/ # HTTP server & WebSocket
│ │ ├── member/ # Auth providers
│ │ ├── plugins/ # Plugin system
│ │ ├── session/ # Session management
│ │ └── webrtc/ # WebRTC (pion)
│ └── pkg/types/ # Shared interfaces
├── client/ # Vue 2 frontend
│ └── src/
│ ├── components/
│ ├── store/ # Vuex modules
│ └── api/ # Axios API client
├── apps/ # Per-browser Docker configs
│ ├── firefox/
│ ├── chromium/
│ └── ...
└── webpage/ # Docusaurus docs site
```

## Tech Stack

### Backend (Go 1.25)
- **Router**: go-chi/chi v5
- **WebRTC**: pion/webrtc v4 (pure Go)
- **WebSocket**: gorilla/websocket
- **Config**: spf13/viper + cobra
- **Logging**: rs/zerolog (structured, use `log.Info().Str("key", val).Msg("...")`)
- **Metrics**: prometheus/client_golang
- **Desktop**: X11/Xorg via CGo bindings
- **Capture**: GStreamer via CGo bindings

### Frontend (TypeScript + Vue 2)
- **Framework**: Vue 2.7 with Class-style components (`vue-class-component` + `vue-property-decorator`)
- **State**: Vuex 3 + typed-vuex
- **Build**: Vue CLI 5 (webpack)
- **Styles**: SCSS

## Build Commands

### Server
```bash
cd server
go build ./... # build
go test ./... # run tests
./dev/build # dev build script
./dev/start # start dev server
./dev/fmt # format (gofmt)
./dev/lint # lint
```

### Client
```bash
cd client
npm install
npm run serve # dev server with HMR
npm run build # production build
npm run lint # ESLint
```

### Docker (full stack)
```bash
docker compose up # uses docker-compose.yaml at root
```

## Server Conventions

### Adding a new API endpoint

1. Add handler method to the relevant controller in `server/internal/api/`
2. Register the route in `server/internal/api/router.go`
3. Follow the existing pattern — handlers receive `(w http.ResponseWriter, r *http.Request)` and use chi's context for path params

```go
// Example handler pattern
func (h *RoomHandler) screenGet(w http.ResponseWriter, r *http.Request) {
session := h.sessions.GetSession(r)
// ... logic
utils.HttpSuccess(w, response)
}
```

### Adding a new plugin

Plugins live in `server/internal/plugins/<name>/`. Each plugin implements the `types.Plugin` interface:

```go
type Plugin interface {
Name() string
Start() error
Stop() error
}
```

Register in `server/cmd/plugins.go`.

### Configuration

All config is in `server/internal/config/`. Each subsystem has its own config struct with viper bindings. Environment variables follow the pattern `NEKO_<SUBSYSTEM>_<FIELD>` (e.g., `NEKO_WEBRTC_EPR`).

### Logging

Use zerolog — never `fmt.Println` or `log.Printf`:

```go
h.logger.Info().Str("session_id", session.ID()).Msg("session connected")
h.logger.Error().Err(err).Msg("failed to process event")
```

## Client Conventions

### Component style

Use Class-style components with decorators:

```typescript
@Component({ components: { MyChild } })
export default class MyComponent extends Vue {
@Prop({ required: true }) readonly value!: string
@Watch('value') onValueChange(val: string) { ... }

get computed() { return this.$store.state.something }
}
```

### Vuex store

Modules live in `client/src/store/`. Use `typed-vuex` accessors — avoid direct `this.$store.commit()` calls; use the typed accessor instead.

### API calls

Use the existing axios client in `client/src/api/`. Don't create new axios instances.

### Styles

- SCSS only, no plain CSS files
- Component-scoped styles with `<style lang="scss" scoped>`
- Global variables/mixins are in `client/src/assets/styles/`

## WebRTC Data Flow

```
GStreamer (X11 capture)
→ pion/webrtc encoder
→ WebRTC video track → browser client

Browser client (mouse/keyboard events)
→ WebRTC DataChannel (binary, big-endian)
→ server/internal/webrtc/handler.go
→ server/internal/desktop/xinput.go (X11 injection)
```

DataChannel messages use a binary header defined in `server/internal/webrtc/payload/`. Always use `binary.BigEndian` for encoding/decoding.

## Testing

### Server tests
```bash
cd server && go test ./...
```

Tests use real structs, not mocks where possible. Integration tests for member providers are in `server/internal/member/file/provider_test.go`.

### Client tests
```bash
cd client && npm test
```

## Common Pitfalls

- **CGo required**: The server uses CGo for X11 and GStreamer. Cross-compiling needs the right CGo toolchain. Use the provided Docker dev environment (`server/dev/runtime/`) for Linux builds.
- **WebRTC port range**: UDP ports `52000-52100` must be exposed in Docker. Set `NEKO_WEBRTC_EPR=52000-52100`.
- **ICE/NAT**: For external access, set `NEKO_NAT1TO1=<public_ip>` or configure a TURN server.
- **Shared memory**: Docker needs `shm_size: 2gb` for browser rendering.
- **Plugin dependency order**: Plugins declare dependencies via `server/internal/plugins/dependency.go`. Circular deps will panic at startup.
40 changes: 40 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# ── Server ────────────────────────────────────────────────────────────────────
# Host port for the web UI
HOST_PORT=8080

# Shared memory size for Chrome rendering
SHM_SIZE=2gb

# ── Auth ──────────────────────────────────────────────────────────────────────
NEKO_USER_PASSWORD=neko
NEKO_ADMIN_PASSWORD=admin

# ── Display ───────────────────────────────────────────────────────────────────
NEKO_DESKTOP_SCREEN=1920x1080@30

# ── WebRTC ────────────────────────────────────────────────────────────────────
NEKO_WEBRTC_EPR=52000-52100
NEKO_WEBRTC_ICELITE=1

# Your server's LAN/public IP — required for WebRTC to work
# Run: ip route get 1 | awk '{print $7}' to find your LAN IP
NEKO_NAT1TO1=192.168.1.100

# ── Video ─────────────────────────────────────────────────────────────────────
NEKO_VIDEO_CODEC=vp8
NEKO_VIDEO_BITRATE=3500
NEKO_MAX_FPS=60

# ── Audio ─────────────────────────────────────────────────────────────────────
NEKO_AUDIO_CODEC=opus
NEKO_AUDIO_BITRATE=196

# ── NVIDIA (nvidia compose only) ──────────────────────────────────────────────
NVIDIA_VISIBLE_DEVICES=all
NVIDIA_DRIVER_CAPABILITIES=all
VGL_DISPLAY=egl

# ── Proxy (optional) ──────────────────────────────────────────────────────────
# HTTP_PROXY=http://proxy.example.com:10809
# HTTPS_PROXY=http://proxy.example.com:10809
# NO_PROXY=localhost,127.0.0.1
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ runtime/icon-theme/*

# root Dockerfile is generated from the Dockerfile.tmpl
/Dockerfile
data/**
.env
48 changes: 48 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
FROM ghcr.io/m1k1o/neko/google-chrome:latest AS builder

ENV DEBIAN_FRONTEND=noninteractive

# Switch to USTC mirror for reliable package downloads
RUN printf 'Types: deb\nURIs: https://mirrors.ustc.edu.cn/debian\nSuites: trixie trixie-updates\nComponents: main\nSigned-By: /usr/share/keyrings/debian-archive-keyring.pgp\n\nTypes: deb\nURIs: https://mirrors.ustc.edu.cn/debian-security\nSuites: trixie-security\nComponents: main\nSigned-By: /usr/share/keyrings/debian-archive-keyring.pgp\n' > /etc/apt/sources.list.d/debian.sources \
&& apt-get update

# Install C build dependencies
RUN apt-get install -y --no-install-recommends \
curl ca-certificates git build-essential \
libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev libxcvt-dev \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
&& rm -rf /var/lib/apt/lists/*

# Install Node.js
RUN apt-get update && apt-get install -y --no-install-recommends nodejs npm \
&& rm -rf /var/lib/apt/lists/*

# Install Go 1.25
RUN curl -fsSL https://go.dev/dl/go1.25.0.linux-amd64.tar.gz -o /tmp/go.tar.gz \
&& tar -C /usr/local -xzf /tmp/go.tar.gz \
&& rm /tmp/go.tar.gz
ENV PATH="/usr/local/go/bin:$PATH"

# Build server
WORKDIR /build/server
COPY server/ .
ENV CGO_ENABLED=1
RUN sed -i 's/\r//' build && bash build

# Build client
WORKDIR /build/client
COPY client/package*.json ./
RUN npm install
COPY client/ .
RUN npm run build

# Final stage: replace binaries in the existing image
FROM ghcr.io/m1k1o/neko/google-chrome:latest
COPY --from=builder /build/server/bin/plugins/ /etc/neko/plugins/
COPY --from=builder /build/server/bin/neko /usr/bin/neko
COPY --from=builder /build/client/dist/ /var/www
# Override Chrome policies and supervisord config
COPY apps/google-chrome/policies.json /etc/opt/chrome/policies/managed/policies.json
COPY apps/google-chrome/supervisord.conf /etc/neko/supervisord/google-chrome.conf
# Override neko config
COPY config.yml /etc/neko/neko.yaml
64 changes: 64 additions & 0 deletions Dockerfile.nvidia-dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
FROM ghcr.io/m1k1o/neko/nvidia-base:latest AS builder

ENV DEBIAN_FRONTEND=noninteractive

# Switch to USTC mirror (Ubuntu 24.04 noble)
RUN sed -i 's|http://archive.ubuntu.com/ubuntu|https://mirrors.ustc.edu.cn/ubuntu|g; s|http://security.ubuntu.com/ubuntu|https://mirrors.ustc.edu.cn/ubuntu|g' \
/etc/apt/sources.list.d/ubuntu.sources \
&& apt-get update

# Install build dependencies
RUN apt-get install -y --no-install-recommends \
curl ca-certificates git build-essential \
libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev libxcvt-dev \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
&& rm -rf /var/lib/apt/lists/*

# Install Node.js
RUN apt-get update && apt-get install -y --no-install-recommends nodejs npm \
&& rm -rf /var/lib/apt/lists/*

# Install Go 1.25
RUN curl -fsSL https://go.dev/dl/go1.25.0.linux-amd64.tar.gz -o /tmp/go.tar.gz \
&& tar -C /usr/local -xzf /tmp/go.tar.gz \
&& rm /tmp/go.tar.gz
ENV PATH="/usr/local/go/bin:$PATH"

# Build server
WORKDIR /build/server
COPY server/ .
ENV CGO_ENABLED=1
RUN sed -i 's/\r//' build && bash build

# Build client
WORKDIR /build/client
COPY client/package*.json ./
RUN npm install
COPY client/ .
RUN npm run build

# Final stage: nvidia-base image with our custom binaries
FROM ghcr.io/m1k1o/neko/nvidia-base:latest

# Switch to USTC mirror in final stage too
RUN sed -i 's|http://archive.ubuntu.com/ubuntu|https://mirrors.ustc.edu.cn/ubuntu|g; s|http://security.ubuntu.com/ubuntu|https://mirrors.ustc.edu.cn/ubuntu|g' \
/etc/apt/sources.list.d/ubuntu.sources

COPY --from=builder /build/server/bin/plugins/ /etc/neko/plugins/
COPY --from=builder /build/server/bin/neko /usr/bin/neko
COPY --from=builder /build/client/dist/ /var/www

# Override Chrome app files
COPY apps/google-chrome/policies.json /etc/opt/chrome/policies/managed/policies.json
COPY apps/google-chrome/supervisord.nvidia.conf /etc/neko/supervisord/google-chrome.conf
COPY apps/google-chrome/openbox.xml /etc/neko/openbox.xml
COPY config.yml /etc/neko/neko.yaml

# Install Google Chrome
ARG SRC_URL="https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"
RUN set -eux; \
apt-get update; \
wget -O /tmp/google-chrome.deb "${SRC_URL}"; \
apt-get install -y --no-install-recommends openbox /tmp/google-chrome.deb; \
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/* /tmp/google-chrome.deb
7 changes: 4 additions & 3 deletions apps/google-chrome/policies.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@
"BrowserAddPersonEnabled": false,
"BrowserGuestModeEnabled": false,
"DefaultPopupsSetting": 2,
"DownloadRestrictions": 3,
"DownloadRestrictions": 0,
"VideoCaptureAllowed": true,
"AllowFileSelectionDialogs": false,
"AllowFileSelectionDialogs": true,
"PromptForDownloadLocation": false,
"BookmarkBarEnabled": false,
"PasswordManagerEnabled": false,
"DefaultClipboardSetting": 1,
"ClipboardAllowedForUrls": ["*"],
"URLAllowlist": [
"file:///home/neko/Downloads"
],
"URLBlocklist": [
Comment on lines +22 to 26
"file://*",
"chrome://policy"
],
"ExtensionInstallForcelist": [
Expand Down
Loading