# 在线代码编辑器 **Repository Path**: xuyang/code-studio ## Basic Information - **Project Name**: 在线代码编辑器 - **Description**: No description available - **Primary Language**: JavaScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-11-03 - **Last Updated**: 2026-11-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Code Studio — 在线代码编辑器(磁盘直读) 浏览器内的迷你 IDE:左侧目录树、右上代码画布、右下终端执行 + AI 助手。目录与文件**直接读写磁盘**(不再走数据库);代码在**容器内的真实工具链**里编译运行(C/C++/Java/Go/Python/Shell/SQL),按「一个学生一个容器」部署。 ``` 在线代码编辑器/ ├── index.html 页面骨架(无内联样式与脚本) ├── start.bat Windows 一键启动(本机模式) ├── package.json npm start / npm run dev ├── Dockerfile 教学环境镜像(Ubuntu 22.04 + Node 22 + gcc/g++ + JDK + Go + Python + bash) ├── docker-compose.yml 单学生环境(含资源限制与加固) ├── assets/ │ ├── css/app.css 全部样式(暗/亮两套主题变量) │ └── js/ │ ├── theme.js 主题模块(head 内同步加载,避免闪屏) │ └── app.js 编辑器主体逻辑 ├── data/ │ ├── settings.json 界面状态(标签页/展开/面板尺寸) │ └── lab.db SQL 实验库(预置教学示例表) ├── server/ │ ├── server.js HTTP 服务 + REST 路由(零第三方依赖) │ ├── workspace.js 磁盘文件系统工作区(目录树/文件读写/增删改/seed) │ ├── runner.js 多语言执行器(临时目录 + 超时强杀 + 输出截断) │ ├── sqlLab.js SQL 实验库(多语句、结果集、一键重置) │ ├── ai.js AI 大模型服务(OpenAI 兼容直连) │ └── seed/ 示例工程(空工作区首次启动时复制到磁盘) └── deploy/ ├── start-students.ps1 Windows 批量开学生容器 └── start-students.sh Linux/macOS 批量开学生容器 ``` ## 工作区(磁盘直读) - **工作区根**:URL 参数 `folder` 优先 → 环境变量 `WORKSPACE` → 平台默认 - Windows:`D:\workspace`(当前开发形态) - Linux/macOS:`/workspace`(容器最终形态) - 目录与文件**直接读写该磁盘目录**,不再持久化到数据库;文件内容**按需读取**(打开时才读,大目录不卡) - 空工作区首次拉取时自动复制 `server/seed/` 示例工程 - 例:`http://127.0.0.1:8080/?folder=D:/workspace/my-project` - 目录树会忽略 `.git`、`node_modules`、`__pycache__` 等;符号链接不跟随 ## 支持的语言与执行方式 | 语言 | 扩展名 | 编辑 | 执行 | 说明 | | --- | --- | --- | --- | --- | | JavaScript | .js .ts | ✅ 高亮 | 浏览器内直接跑 | 同目录 HTML 引用时自动转页面预览 | | HTML / CSS | .html .css | ✅ 高亮 | 沙箱 iframe 预览 | 本地 link/script 自动内联 | | Python | .py | ✅ 高亮 | 容器内 python3(无后端时退回 Pyodide) | 工作目录 = 脚本所在目录 | | C | .c .h | ✅ 高亮 | 容器内 gcc(c11,-O2) | 入口目录下所有 .c 一起编译 | | C++ | .cpp .cc .cxx | ✅ 高亮 | 容器内 g++(c++17,-O2) | 同上(.cpp/.cc/.cxx) | | Java | .java | ✅ 高亮 | 容器内 javac + java(UTF-8) | 入口类 = 文件名;全项目 .java 一起编译 | | Go | .go | ✅ 高亮 | 容器内 go run | 只编译入口目录的包;GOPROXY=off 仅标准库 | | SQL | .sql | ✅ 高亮 | 实验库 lab.db(node:sqlite) | 多语句、结果表格、JOIN/DDL/DML 均可 | | Shell | .sh .bash | ✅ 高亮 | 容器内 bash | 真实 Linux 命令(容器内才有 ps/chmod 等语义) | 执行保护(`server/runner.js`):每次运行独立临时目录、进程树超时强杀(运行 10s / 编译 30s)、输出 256KB 截断、最小环境变量(不透传宿主密钥)、同一学生同时只跑一个程序。 ## 界面功能 - **主题切换**:顶栏 ◐/☀/☾ 按钮,循环「跟随系统 → 明亮 → 暗色」,默认跟随浏览器/系统(`prefers-color-scheme`),选择存在 localStorage;系统主题变化时 auto 模式实时跟随 - **目录树行内操作**:悬停文件夹行显示「新建文件 / 新建文件夹 / 重命名 / 删除」四个按钮,新建动作直接作用于该文件夹;文件行为「重命名 / 删除」;删除为红色垃圾桶图标 - 顶部资源管理器工具栏的「+ / 文件夹+」按钮作用于当前选中的文件夹(未选中则为根目录) - 新建 `.c/.cpp/.java/.go/.py/.sh/.sql` 文件时自动填入可运行的起步模板 - 终端命令新增:`sql <语句>`(直接执行 SQL)、`tables`(看实验库表)、`dbreset`(重置实验库) ## AI 助手(右侧对话面板) 顶栏 ✨ 按钮开关右侧 AI 面板,与 AI 大模型对话完成代码编写:AI 回复中的代码块带「插入到编辑器」按钮,支持选中代码后一键「解释 / 修复 / 补充注释」。 - **零依赖开箱即用**:只要填好 `baseUrl`、`model`、`apiKey` 三项,即可直连任意 OpenAI 兼容大模型,**无需安装任何 CLI** - **配置**:左侧目录树里的 `ai.config.json`(可直接编辑),只含三个字段: ```json { "baseUrl": "https://api.deepseek.com", "model": "deepseek-flash", "apiKey": "" } ``` - **baseUrl**:支持裸域名、带 `/v1`、完整 `/chat/completions` 三种写法,后端会自动归一化 - **模型 id**:DeepSeek 端点支持 `deepseek-flash`(免费档)与 `deepseek-v4-pro`;后端做了别名兼容,写 `DeepSeek V4 Flash Free` 也会自动纠正为 `deepseek-flash` - `apiKey` 建议走环境变量 `DEEPSEEK_API_KEY`(容器部署时注入),不落到项目文件里;`GET /api/ai/config` 返回的 key 已脱敏 相关接口:`GET/PUT /api/ai/config`、`POST /api/ai/chat`(SSE 流式,请求体 `{messages:[{role,content}]}`)。 ## 启动 ```bash # 方式一:双击 start.bat # 方式二: npm start # 等价于 node --no-warnings server/server.js # 然后浏览器打开 http://127.0.0.1:8080 ``` 环境要求:**Node.js ≥ 22.5**(使用内置 `node:sqlite` 做 SQL 实验库,无需 `npm install`)。 - 通过 `http://127.0.0.1:8080` 打开 → 状态栏显示 `● 磁盘 · <工作区路径>`,目录文件直接读写磁盘 - 直接双击 `index.html`(`file://`)→ 会自动尝试连接本机 8080;连不上则显示 `● 本地 · localStorage` - 环境变量:`PORT=8081`、`HOST=0.0.0.0`、`WORKSPACE=D:/path`(覆盖默认工作区)、`LAB_DB`、`LOG=0`(关闭访问日志) ## API 基址 `http://127.0.0.1:8080`,全部返回 JSON;已开启 CORS,`file://` 页面也可调用。所有工作区相关接口都接受 `?folder=<路径>` 指定工作区根。 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/api/health` | 健康检查 + 工作区路径 + 数据统计 | | GET | `/api/workspace` | 目录树(不含内容,文件按需读)+ 界面设置 | | GET | `/api/tree?withContent=1` | 目录树(默认不含内容) | | GET | `/api/nodes?path=src` | 列出某目录下的直接子节点 | | GET | `/api/file?path=src/app.js` | 读取单个文件内容 | | PUT | `/api/file` | 保存内容 `{path, content}`,父目录不存在时自动补建 | | POST | `/api/node` | 新建 `{parentPath, name, type, content?}` | | PATCH | `/api/node` | 重命名 `{path, name}` 或改内容 `{path, content}` | | DELETE | `/api/node?path=src/app.js` | 删除文件或整个目录 | | GET | `/api/settings` | 读取界面设置 | | PUT | `/api/settings` | 写入界面设置 `{settings:{...}}` | | POST | `/api/seed` | 清空工作区并用 `server/seed/` 重新写入示例工程 | | POST | `/api/run` | 编译并运行 `{path, stdin?}`(C/C++/Java/Go/Python/Shell) | | POST | `/api/sql` | 执行 SQL `{sql}` 或 `{path}`,结果带行列信息 | | GET | `/api/sql/tables` | 列出实验库中的表 | | POST | `/api/sql/reset` | 实验库重置为教学示例表 | `GET /api/health` 返回 `run.languages`,即各工具链的探测结果(✓/✗),前端据此提示缺什么编译器。 ### 示例 ```bash curl http://127.0.0.1:8080/api/health curl -X POST http://127.0.0.1:8080/api/node \ -H "Content-Type: application/json" \ -d '{"parentPath":"src","name":"demo.js","type":"file"}' curl -X PUT http://127.0.0.1:8080/api/file \ -H "Content-Type: application/json" \ -d '{"path":"src/demo.js","content":"console.log(1)"}' curl "http://127.0.0.1:8080/api/file?path=src/demo.js" curl "http://127.0.0.1:8080/api/revisions?path=src/demo.js" curl -X PATCH http://127.0.0.1:8080/api/node \ -H "Content-Type: application/json" \ -d '{"path":"src/demo.js","name":"renamed.js"}' curl -X DELETE "http://127.0.0.1:8080/api/node?path=src/renamed.js" ``` 错误统一为 `{ok:false, error:"..."}`,状态码语义:`400` 参数错、`404` 不存在、`409` 重名、`413` 请求体过大、`500` 服务端异常。 ## 前端如何接后端 `assets/js/app.js` 内的存储适配层: 1. 启动时 `GET /api/health` 探测后端(`file://` 下按 `127.0.0.1:8080`、`localhost:8080` 依次尝试) 2. 探测成功 → `GET /api/workspace` 载入目录树(不含内容)与界面状态,标记 `remote` 模式 3. 打开文件时按需 `GET /api/file` 拉取内容;每次编辑先写 localStorage 兜底,再 320ms 节流 `PUT /api/file` + `PUT /api/settings` 4. 新建/重命名/删除:`POST/PATCH/DELETE` 后重新拉取 `/api/workspace` 重建界面 5. 探测失败 → 完整退回 localStorage 模式,功能不降级(只是不落盘、不共享) 6. 所有请求自动附加 `?folder=<工作区>` 参数(取自页面 URL) 终端里输入 `sync` 可手动从服务器重新拉取。 ## 容器部署(一个学生一个环境) **镜像内置工具链**:基于 `public.ecr.aws/ubuntu/ubuntu:22.04`,装 Node 22(NodeSource)+ gcc/g++(C/C++)+ OpenJDK 17(Java)+ Go + Python3 + bash 与 Linux 课程常用命令(ps/top/awk/sed/tar/file 等)。23 个 apt 包名已逐一核对存在于 Ubuntu 22.04(jammy),NodeSource 与 ECR 镜像标签也已联网确认。 ```bash # 1. 构建镜像 docker build -t code-studio:1.0 . # 2. 单个学生(本机体验) docker compose up -d # http://localhost:8080 # 3. 批量开学生环境 # Windows(PowerShell): deploy\start-students.ps1 -Count 40 # cs-01..cs-40,端口 9001..9040 deploy\start-students.ps1 -Count 40 -Stop # 停止(保留学生数据) deploy\start-students.ps1 -Count 40 -Purge # 连数据卷一起删(彻底重置) # Linux / macOS: deploy/start-students.sh 40 ``` **每个容器 = 一份完全隔离的环境**: | 维度 | 实现 | | --- | --- | | 文件 | 工作区卷 `cs-XX-workspace:/workspace`(学生代码,磁盘直读)+ 数据卷 `cs-XX-data:/app/data`(界面设置 + SQL 实验库) | | CPU/内存 | `--cpus 1 --memory 1g`,防止单个学生拖垮宿主机 | | 进程 | `--pids-limit 256`,fork 炸弹无效;程序层另有 10s 运行超时强杀 | | 文件系统 | `--read-only`(根只读)+ `/tmp` tmpfs 256MB(编译产物落这里) | | 提权 | `--cap-drop ALL --security-opt no-new-privileges`,非 root 运行 | | 网络 | 容器间互不可见(各自独立 IP);如需禁止学生容器出网,在宿主防火墙/安全组上按端口段拦截 | **注意事项**: - `/tmp` 的 tmpfs **不能加 `noexec`**,否则 C/C++ 编译出的程序无法执行 - jammy 自带 Go 1.18,教学够用;`runner.js` 会按镜像内实际 Go 版本生成 `go.mod` 的 `go` 指令。需要 Go 1.22+ 时按 Dockerfile 里的注释改用官方 tarball - Java 教学约定:`public class` 名必须与文件名一致(`Main.java` → `class Main`),编译错误会直接显示在终端 - SQL 实验库 `lab.db` 独立于工作区,且已禁止 `ATTACH` 外部数据库;预置表:`devices` / `work_orders` / `qc_records` - `ALLOW_RUN=0` 环境变量可整体关闭服务端执行(只保留编辑与预览) - 宿主机直接跑(不经容器)时,缺 gcc 会得到明确提示;Java/Go/Python/Shell 本机装了即可用 **镜像构建**:已在远程服务器(阿里云 ECS,Ubuntu 24.04 + Docker 29.9)成功构建并验证: ```bash docker build -t code-studio:0.0.1 . # 磁盘占用约 1.79GB(内容 454MB),含 gcc 11.4 / JDK 17 / Go 1.18 / Python 3.10 / Node 22 ``` 容器启动即健康,`/api/health` 返回 6 种语言工具链(C/C++/Java/Go/Python/Shell)全部可用。 > 构建要点:基础镜像 `public.ecr.aws/ubuntu/ubuntu:22.04` 自带的旧 Python 字节码缓存会与 apt 升级后的 3.10.12 冲突,Dockerfile 已用 `find /usr/lib/python3* -name '*.pyc' -delete` 清理;本地 Docker Desktop(WSL2 后端、2GB 内存)构建时引擎会崩溃,建议用内存 ≥4GB 的 Linux 主机构建。