介绍
最近在为自己学校的比赛部署一个 xcpcio board 以用于保存历史比赛数据,但是目前没看到任何详细的部署文档,只有 hub docker上的 xcpcio/xcpcio images
经过 1145秒 阅读dockerfile 后,发现这个images实际上是一个构建镜像,用于将 XCPCIO 源码编译成静态文件,并根据环境变量注入配置
也就是说我们只需要拉取镜像下来运行一次,获得构建的结果即可,随后通过 nginx 反向代理即可
/app/xcpcio/packages/apps/board/scripts/../dist/index.html/app/xcpcio/packages/apps/board/scripts/../dist/sw.jsExported /app/xcpcio/docker/../packages/apps/board/dist to /app/export构建
我这边由于学校内网结构比较复杂,宿舍网段是 172.17.0.0/16,而docker默认创建的也是172.17.0.0/16,所以就导致出现了宿舍无法访问机房机器
docker-compose
在某个空白文件夹中创建 docker-compose.yml 文件即可,填入以下内容:
services: xcpcio-builder: image: xcpcio/xcpcio:0.84.0 container_name: xcpcio-builder environment: APP: board BOARD_DATA_HOST: "/data" # 这里 BOARD_DATA_REGION: "CN" BOARD_DEFAULT_LANG: "zh" BOARD_REFETCH_INTERVAL: "5000" # 榜单内拉取服务器信息频率(ms毫秒) volumes: - ./export:/app/export command: primary如果你学校和我一样是 172.17.0.0/16 则使用下面的yml文件
services: xcpcio-builder: image: xcpcio/xcpcio:0.84.0 container_name: xcpcio-builder environment: APP: board BOARD_DATA_HOST: "/data" # BOARD_DATA_REGION: "CN" BOARD_DEFAULT_LANG: "zh" BOARD_REFETCH_INTERVAL: "5000" # 榜单内拉取服务器信息频率(ms毫秒) volumes: - ./export:/app/export networks: xcpcio-net: ipv4_address: 172.29.0.3 command: primary
networks: xcpcio-net: driver: bridge ipam: config: - subnet: 172.29.0.0/16 gateway: 172.29.0.1在控制台运行 docker-compose up -d 即可在 docker-compose.yml 同一文件夹下看到 export的文件夹

docker
这里如果你是172.17.0.0/16网段,我还是建议你使用 docker-compose.yml的方法
# 创建输出目录mkdir -p ./export
# 运行构建docker run --rm \ -e APP=board \ -e BOARD_DATA_HOST="/data" \ -e BOARD_DATA_REGION="CN" \ -e BOARD_DEFAULT_LANG="zh" \ -e BOARD_REFETCH_INTERVAL="5000" \ -v $(pwd)/export:/app/export \ xcpcio/xcpcio:0.84.0 primary
# 查看生成的文件ls -la ./export/运行结果如图

部署上线
这里只介绍反向代理怎么写。
我们使用 nginx 创建一个反向代理,这里的 proxy_pass 指向的是我们校内的数据服务器
location /data { proxy_pass http://127.0.0.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; proxy_http_version 1.1; add_header X-Cache $upstream_cache_status; add_header Cache-Control no-cache; proxy_ssl_server_name off; proxy_ssl_name $proxy_host;}数据服务器
xcpcio 是通过python自带的http server 来实现的数据服务器。
python \ -m http.server \ $@ \ 8080我们的自定义数据服务器必须要提供索引文件,服务器的结构如下
board-data:.├─data│ └─index│ └─contest_list.json其中 contest_list.json 为索引文件,用于显示主页目录条目的,其中包括每个比赛的数据路径

比赛路径必须是其中之一(你也可以自己去魔改代码)
const contestTypes = [ "camp", "icpc", "ccpc", "provincial-contest",];
const isNotFound = !contestTypes.some(c => route.fullPath.startsWith(`/${c}`));contest_list.json格式
从代码定义的类型可以知道
export function createContestIndexList(contestListJSON: any): ContestIndexList { const contestIndexList = [] as ContestIndexList;
const dfs = (contestList: any) => { if (Object.prototype.hasOwnProperty.call(contestList, "config")) { contestIndexList.push(createContestIndex(contestList)); } else { for (const k in contestList) { dfs(contestList[k]); } } };
dfs(contestListJSON);
contestIndexList.sort((a: ContestIndex, b: ContestIndex) => { if (a.contest.startTime.isBefore(b.contest.startTime)) { return 1; }
if (a.contest.startTime.isAfter(b.contest.startTime)) { return -1; }
if (a.contest.endTime.isBefore(b.contest.endTime)) { return 1; }
if (a.contest.endTime.isAfter(b.contest.endTime)) { return -1; }
if (a.contest.name < b.contest.name) { return 1; }
if (a.contest.name > b.contest.name) { return -1; }
return 0; });
return contestIndexList;}我们则可以得到一个比较简单的可用配置(实际下面的是复制contest.json里的)
{ "icpc": { "50th": { "xian": { "config": { "contest_name": "第 50 届 ICPC 国际大学生程序设计竞赛西安站", "start_time": 1760835600000, "end_time": 1760853600000, "frozen_time": 3600000, "logo": { "preset": "ICPC" } }, "board_link": "/icpc/50th/xian" } }, }, "ccpc": { "10th": { "zhengzhou": { "config": { "contest_name": "第 11 届 CCPC 中国大学生程序设计竞赛郑州站 - 正式赛", "start_time": 1763859600000, "end_time": 1763877600000, "frozen_time": 3600, "logo": { "preset": "CCPC" } }, "board_link": "/ccpc/11th/zhengzhou" } } }}我们可用从json数据得到 board_link , 这个则是homepage点击跳转的链接,获取对应比赛也会依据这个path获得对应的
- team.json
- run.json
- config.json
上面的具体格式,docs中亦有记载 link
我们的任务就是将学校oj的数据转化为符合规范的json数据即可。
部分信息可能已经过时









