feat: enhance completion service with session management and language support

- Introduced session management using Redis for tracking active sessions.
- Added session claiming and releasing functionality in the completion manager.
- Enhanced HTTP and WebSocket completion endpoints to support multiple languages.
- Implemented request timeout and maximum body size configurations for API routes.
- Updated client-side code to handle session IDs and language parameters in completion requests.
- Improved error handling for unsupported languages and session conflicts.
- Added tests for the completion manager to ensure proper session handling and cleanup.
This commit is contained in:
2026-02-15 16:22:01 +08:00
parent 23decb8687
commit 57afb90bc0
14 changed files with 1334 additions and 138 deletions

View File

@@ -1,6 +1,14 @@
# Monaco Go Completion Backend
# Monica LSP Gateway
Gin + gopls(JSON-RPC/LSP over stdio) 实现的 Go 代码补全后端。
面向微服务场景的 LSP 网关Gin当前支持
- Go: `gopls`
- JavaScript / TypeScript: `typescript-language-server --stdio`
网关职责:
- 对外提供 HTTP + WebSocket 接口
- 对内通过 JSON-RPC / LSP over stdio 驱动语言服务器
-`language + sessionId` 维护长生命周期会话
- 会话空闲自动回收TTL
## 运行
@@ -9,80 +17,102 @@ go mod tidy
go run ./cmd/server
```
默认监听 `http://localhost:8080`
默认地址:`http://127.0.0.1:8080`
## 环境变量
## 企业化配置(环境变量
- `PORT`HTTP 端口,默认 `8080`
- `GOPLS_PATH``gopls` 可执行文件路径,默认 `gopls`
- `WORKSPACE_DIR`gopls 工作目录,默认当前目录
- `CORS_ALLOW_ORIGIN`CORS 允许来源,默认 `*`
- `PORT`:默认 `8080`
- `WORKSPACE_DIR`LSP 工作目录,默认当前目录
- `CORS_ALLOW_ORIGIN`:默认 `*`
- `LSP_API_TOKEN`:可选,设置后需在请求头传 `X-API-Key`
- `REQUEST_TIMEOUT`:单请求超时,默认 `10s`
- `MAX_BODY_BYTES`:请求体上限,默认 `2097152`2MB
- `SESSION_TTL`:会话空闲回收时间,默认 `20m`
- `SESSION_CLEANUP_INTERVAL`:清理周期,默认 `2m`
- `MAX_SESSIONS`:最大会话数,默认 `256`
- `ENABLE_REDIS_STICKY`:是否启用 Redis 会话外置与粘性路由,默认 `true`
- `REDIS_ADDR`:默认 `10.0.0.10:6379`
- `REDIS_DB`:默认 `1`
- `REDIS_PASSWORD`:默认空
- `REDIS_KEY_PREFIX`:默认 `lsp-gateway`
- `INSTANCE_ID`:实例唯一标识(建议由部署系统注入)
- `INSTANCE_URL`:实例可回源地址(用于路由提示),默认 `http://127.0.0.1:${PORT}`
- `INSTANCE_TTL`:实例注册 TTL默认 `30s`
- `INSTANCE_HEARTBEAT_INTERVAL`:实例心跳周期,默认 `10s`
## API
语言服务器命令(可替换为企业内部镜像/封装):
- `GO_LSP_COMMAND``GO_LSP_ARGS`
- `JAVASCRIPT_LSP_COMMAND``JAVASCRIPT_LSP_ARGS`
- `TYPESCRIPT_LSP_COMMAND``TYPESCRIPT_LSP_ARGS`
### 健康检查
默认 JS/TS 命令:
- `typescript-language-server --stdio`
## 健康检查
- `GET /health`
- `GET /health/live`
- `GET /health/ready`(含当前会话统计)
### Go 补全
## HTTP 补全接口
- `POST /api/v1/completions/go`
- `Content-Type: application/json`
- `POST /api/v1/completions/:language`
### Go 补全WebSocket
示例JavaScript
- `GET /ws/completions/go`
- 客户端发送:
```json
{
"sessionId": "editor-1",
"language": "javascript",
"uri": "file:///main.js",
"text": "const a = console.lo",
"line": 0,
"character": 20
}
```
## WebSocket 接口
- `GET /ws/completions`
- `GET /ws/completions/:language`
支持两种消息格式:
1) 简化消息:
```json
{
"id": "1",
"sessionId": "editor-1",
"language": "go",
"uri": "file:///main.go",
"text": "package main\n\nimport \"fmt\"\n\nfunc main() {\n fmt.Pri\n}",
"text": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Pri\n}",
"line": 5,
"character": 11
"character": 9
}
```
- 服务端返回
2) JSON-RPC 风格
```json
{
"id": "1",
"items": [{ "label": "Println" }],
"isIncomplete": false
"jsonrpc": "2.0",
"id": 1,
"method": "completion/complete",
"params": {
"sessionId": "editor-1",
"language": "typescript",
"uri": "file:///main.ts",
"text": "console.lo",
"line": 0,
"character": 10
}
}
```
请求体:
## 备注
```json
{
"uri": "file:///C:/Users/meowr/Desktop/bishe/monica_editor_with_code_completion/backend/playground.go",
"text": "package main\n\nimport \"fmt\"\n\nfunc main() {\n fmt.Pri\n}",
"line": 5,
"character": 11
}
```
说明:
- `uri` 建议使用绝对 `file://` URI`WORKSPACE_DIR` 在同一工作区最稳定)。
- 也支持 `file:///main.go` 这类相对根路径 URI后端会自动映射到 `WORKSPACE_DIR` 下。
- `line` / `character` 为 0-based。
- 每次请求都要传前端当前全文 `text`
响应体:
```json
{
"items": [
{
"label": "Println",
"kind": 3,
"detail": "func(a ...any) (n int, err error)",
"documentation": "Println formats using the default formats..."
}
],
"isIncomplete": false
}
```
- `uri` 支持 `file:///main.go` 这类相对根路径,网关会映射到 `WORKSPACE_DIR`
- 前端建议稳定传 `sessionId`,避免频繁新建语言服务器进程。
- 多实例场景下,如果请求落到非会话所属实例,服务会返回 `409` 并携带 `routeTo``X-LSP-Route-To`