hzauoj-vscode-extension(HOJ 公开题库)
用你自己的 SSH 私钥登录 HOJ,在 VS Code 侧边栏浏览主站公开题目,已通过的题目前显示绿色对勾,
题面默认用 Markdown Preview 渲染,可把样例一键导入 Competitive Programming Helper (CPH),
也能直接提交代码并等待判题结果。支持「只看未通过」筛选,方便顺着往下练。
插件走的是站点的开放接口(挑战 → 签名 → 短期令牌),不需要也不保存站点账号密码。
本仓库是 HOJ 开放接口的独立客户端,服务端协议见 HOJ 主仓库的
docs/docs/use/ssh-open-api.md(https://gitee.com/vanadium_23/hoj)。
前置条件
- 站点管理员在 管理后台 → 系统配置 → 系统开关 → SSH 公钥开放接口 打开开关(默认关闭)。
- 你在 个人设置 → SSH 密钥 里登记了将要用到的公钥(每人最多 10 把)。
插件只用私钥本地签名,私钥不会离开你的电脑。
- 如果想提交代码:账号需未被封禁、角色权限里有「提交题目」,且站点总开关
openPublicJudge 开启;
提交与网页共用账号级提交间隔,另有每把密钥每分钟 10 次的限制。
- 如果想导入样例到 CPH:先装好
Competitive Programming Helper,
并打开一个文件夹作为工作区(CPH 会把解题文件与样例放在工作区里)。
准备一把专用密钥(推荐)
ssh-keygen -t ed25519 -N "" -f ~/.ssh/hoj_openapi
# 把公钥内容粘贴到「个人设置 → SSH 密钥」
cat ~/.ssh/hoj_openapi.pub
支持 Ed25519、RSA(≥2048 位)、ECDSA P-256/P-384/P-521。加密的 OpenSSH 私钥暂不支持
(Node 没有内置 bcrypt_pbkdf);带口令的 PEM/PKCS#8 私钥会弹窗询问口令,口令只在当前窗口内保留。
安装
方式一:直接安装 VSIX(推荐)
仓库的 dist/ 目录随版本提供打包好的 VSIX,下载后任选一种安装方式:
Gitee 的 VSIX 直链(版本号按 dist/ 里的实际文件替换):
https://gitee.com/vanadium_23/hzauoj-vscode-extension/raw/master/dist/hzauoj-vscode-extension-0.4.0.vsix
方式二:F5 调试运行(开发者)
git clone git@gitee.com:vanadium_23/hzauoj-vscode-extension.git
用 VS Code 打开仓库根目录,按 F5 启动扩展开发宿主(.vscode/launch.json 已配好),
在弹出的新窗口里使用插件。这种方式改代码后重新按 F5 即可,不用打包。
方式三:自行打包
npm run package # 产物在 dist/hzauoj-vscode-extension-<版本>.vsix
code --install-extension dist/hzauoj-vscode-extension-0.4.0.vsix
插件没有运行时依赖,不需要 npm install;打包用的是 npx @vscode/vsce(首次会临时下载)。
使用
- 点击活动栏的「HOJ 公开题库」图标(或命令面板
HOJ: 配置 OJ 地址与私钥)。
- 填站点地址(例如
http://127.0.0.1 或 https://acm.example.com,不要带 /api)与私钥路径。
- 插件自动登录,侧边栏列出公开题目;点击题目拉取题面,Markdown 会保存在扩展的全局存储目录,
默认用 Markdown Preview 渲染(想看 markdown 源码就把
hojOpenApi.problemOpenMode 改成 source)。
- 「加载更多」按页追加,搜索支持按展示 ID / 标题过滤。
- 在题目节点上点「导入样例到 CPH」内联按钮,直接导入该节点这道题;从命令面板执行
HOJ: 导入样例到 CPH 才会让你选一道题。
- 提交代码:打开代码文件后执行
HOJ: 提交当前文件到 OJ,或点题目节点上的云上传内联按钮
(同样直接提交到该题,不再重复选题)。
- 想专挑没做出的题练:点视图标题栏的漏斗按钮切「只看未通过」;状态栏会显示当前账号与通过数。
做题状态:一眼看出哪些题已经过了
题目图标分三种状态,鼠标悬停能看到「我的状态」的具体文字:
| 图标 |
含义 |
悬停文字 |
| 绿色对勾 |
已通过(Accepted) |
已通过(Accepted) |
| 琥珀色圆点 |
交过但没过 |
最近一次 Wrong Answer 等 |
| 文档 / 云 |
还没交过(云 = 远程评测题) |
未提交 |
- 状态来自服务端的
myStatus 字段,在网页上 AC 的题这里同样显示对勾,不是只记插件自己的提交。
- AC 过就永久算通过:之后又交了一发 WA,对勾不会消失(与站点题库口径一致)。
- 按「逻辑题目」聚合:主站原题和引用它的团队题算同一道,AC 任一道都算通过。
- 判题一出结论就就地更新该题图标,不用为了看一个对勾去刷新整页。
- 状态栏
HOJ 已通过/已加载 常驻,悬停显示登录账号、站点总题数与当前筛选,点一下即刷新。
只看未通过 / 只看已通过
视图标题栏的漏斗按钮(HOJ: 按做题状态筛选)提供三个选项:全部题目 / 只看未通过 / 只看已通过。
- 筛选由服务端完成(列表接口的
solved 参数),所以「加载更多」的已显示条数与总数仍然准确;
如果只在本地过滤已加载的那几页,翻页就会错位。
- 筛选与搜索关键字可以叠加;列表顶部会显示当前的关键字与筛选,点一下即可修改。
- 筛选后没有结果时,文案会区分「还没有已通过的公开题目」「公开题目都已通过」和「暂无公开题目」。
提交代码并等待判题结果
- 语言按当前文件扩展名在该题的可用语言里挑一个(
.cpp 优先 C++ 17 With O2,.py 优先 Python3 …),
挑不到就弹 QuickPick 让你选;未知扩展名与空文件不会提交。
- 提交前会弹模态确认框,写清文件、题目与语言,避免误交。
- 提交成功后每 1.5 秒轮询一次判题状态(最多约 5 分钟,可取消),结束时弹窗给出结果与耗时/内存,
并附「在浏览器中查看」按钮打开该提交详情页。编译错误等
errorMessage 会写进输出面板。
- 提交记录与网页提交一致:代码默认仅自己可见、不算验题、不能指定比赛或团队;
开放接口只能提交主站公开题。
- 状态轮询走独立的 120 次/分/密钥配额,不会把题面接口的 60 次/分打满。
导入样例到 CPH
插件会把题目标题、站点链接、时间/内存限制和全部样例 POST 给 CPH 的本地 Companion 端口
(默认 http://127.0.0.1:27121),由 CPH 自己创建/打开解题文件并切到测试用例面板。
这里没有直接写 CPH 的 .cph/*.prob 文件:它的文件名按解题源文件的 md5 生成,
走导入协议才能同时让 CPH 刷新界面。
- 必须先打开一个文件夹;没打开时插件会直接提示,不会发请求。
- 题面没有样例时不会导入,并给出警告。
- 导入后 CPH 若弹出语言选择,按它的提示选即可(可在 CPH 设置里指定默认语言,避免每次询问)。
- 本机改了 CPH 的端口时,同步修改
hojOpenApi.cphUrl。
配置项
| 配置 |
默认 |
说明 |
hojOpenApi.baseUrl |
空 |
OJ 站点地址;结尾的 / 与误粘的 /api 会自动去掉 |
hojOpenApi.privateKeyPath |
空 |
私钥路径,支持 ~ 与工作区相对路径 |
hojOpenApi.timeoutMs |
15000 |
单次请求超时(毫秒) |
hojOpenApi.pageSize |
20 |
每页题目数,服务端单页上限 50 |
hojOpenApi.cphUrl |
http://127.0.0.1:27121 |
CPH 的本地 Companion 端口,通常无需修改 |
hojOpenApi.problemOpenMode |
preview |
题面视图:preview = Markdown Preview(默认),source = 直接打开 .md 源文件;内置 Markdown 扩展不可用时自动回退源码视图 |
命令
| 命令 |
说明 |
HOJ: 配置 OJ 地址与私钥 |
保存配置并尝试登录 |
HOJ: 登录(SSH 密钥换令牌) |
手动换令牌,并显示账号、指纹与剩余有效期 |
HOJ: 退出登录(清除本会话令牌) |
只删内存里的令牌,不影响已登记的公钥 |
HOJ: 刷新题目列表 / HOJ: 加载更多题目 |
重新拉取 / 追加下一页 |
HOJ: 搜索题目 |
关键字过滤,留空清除 |
HOJ: 按做题状态筛选(全部/未通过/已通过) |
服务端按是否 AC 过滤,分页条数仍准确 |
HOJ: 打开题目题面 |
拉取 detail.md,默认用 Markdown Preview 打开 |
HOJ: 导入样例到 CPH |
把题目与全部样例交给 CPH,由 CPH 建解题文件并显示测试用例 |
HOJ: 提交当前文件到 OJ |
按扩展名选语言、确认后提交,并轮询判题结果 |
HOJ: 在浏览器中打开题目 |
跳站点题目页看讨论、榜单与提交历史(开放接口不提供这些) |
安全说明
- 令牌是不透明随机串,只存在内存,默认 1 小时过期;插件在过期前 30 秒自动重新换。
- 服务端每次请求都会回查公钥是否还在,在「SSH 密钥」里删掉公钥,手里令牌立刻失效;
插件遇到 401 会静默重登一次,公钥已被删就会直接报错。
- 令牌 scope 为
problem:read problem:submit:只能读公开题、向公开题提交、查自己的提交状态。
- 限流:挑战 30 次/分/IP、换令牌 10 次/分/IP、题目接口 60 次/分/密钥、提交 10 次/分/密钥、
状态查询 120 次/分/密钥。
- 重定向最多跟 3 跳;跨主机(
host:port 变化)时自动去掉 Authorization,避免令牌被引到别的服务。
- 私钥路径只是本地配置,不会上传;但请勿把私钥提交进仓库(建议专门生成一把无口令密钥)。
常见错误
| 现象 |
处理 |
SSH 公钥与开放接口当前未开启 |
让管理员打开系统开关 |
无法解析私钥 ... NO_START_LINE |
路径多半指到了 .pub 公钥(或 PuTTY .ppk)。把 .pub 去掉,指向私钥,例如 ~/.ssh/id_ed25519 |
签名校验失败 / 指纹未登记 |
确认登记的是这把私钥对应的公钥,且类型/位数受支持 |
私钥已加密(OpenSSH 格式) |
改用无口令专用密钥;或把私钥转成加密 PEM 后由插件询问口令 |
请求过于频繁 |
等一分钟;频繁点「刷新」会消耗挑战/换令牌配额 |
加载失败:连接 ... 失败 |
检查地址、端口与 HTTPS 证书;插件不会忽略证书错误 |
未安装 Competitive Programming Helper |
先安装并启用 CPH,再重试导入 |
无法连接 CPH(http://127.0.0.1:27121) |
CPH 没在运行(重载窗口)或改了端口;端口不同就改 hojOpenApi.cphUrl |
请先打开一个文件夹 |
CPH 需要工作区来放解题文件;先打开一个文件夹再导入 |
请先打开要提交的代码文件 |
提交命令针对当前编辑器里的文件;先打开并选中代码文件 |
当前文件是空的 |
文件没有内容;写好代码再提交 |
| 提交时弹出语言选择框 |
扩展名没有匹配到该题支持的语言(如 .txt);选一个即可,或改用 .cpp/.py/.java 等扩展名 |
没有提交题目的权限 / 该账户已被封禁 |
找管理员确认角色权限与账号状态 |
您的提交频率过快 |
站点设置的账号级提交间隔未到;网页提交也受同一把锁 |
提交过于频繁:每把密钥每分钟最多 10 次 |
等一分钟再交;状态轮询不受这条限制 |
自测
npm test
以 ssh-keygen 与 openssl 为地面真值核对指纹与签名,并起一个本地假 HOJ 跑完整的
挑战 → 签名 → 换令牌 → 拉列表 / 题面 → 提交 → 轮询判题链路;CPH 导入用随机端口的假 Companion 服务
验证请求体与失败分支;另用假 vscode 模块验证命令接线、401 自动重登、题面落盘、Markdown Preview
默认视图与提交确认 / 语言推断 / 结果轮询,以及侧边栏内联按钮传 TreeItem 时不再重复弹选题框;
做题状态部分覆盖对勾 / 尝试过 / 未做过的图标与主题色、AC 永久保留、判题后就地刷新(不重拉列表)、
状态栏账号与通过数、服务端 solved 筛选与空结果文案(209 项断言)。