Skip to content

Commit

Permalink
feat(socket-io): add competition controller and docker compose file
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamerblue committed Apr 12, 2024
1 parent 05771ff commit 5376636
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 36 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/socket-io.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Build Socket.IO Docker Image
on:
push:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-push:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./src/sub-app/socket-io
steps:
- name: Checkout
uses: actions/checkout@v3
# - uses: actions/setup-node@v3
# with:
# node-version: 16
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to TCR
uses: docker/login-action@v2
with:
registry: ccr.ccs.tencentyun.com
username: ${{ secrets.TCR_USERNAME }}
password: ${{ secrets.TCR_TOKEN }}
- name: Build and Push Image
uses: docker/build-push-action@v3
with:
context: ./src/sub-app/socket-io
file: ./src/sub-app/socket-io/Dockerfile
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/onlinejudge3-socket-io:1
${{ secrets.DOCKERHUB_USERNAME }}/onlinejudge3-socket-io:latest
ccr.ccs.tencentyun.com/${{ secrets.TCR_NSP }}/onlinejudge3-socket-io:1
ccr.ccs.tencentyun.com/${{ secrets.TCR_NSP }}/onlinejudge3-socket-io:latest
17 changes: 17 additions & 0 deletions src/sub-app/socket-io/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM sdutacm/nodebase:16.15.0

WORKDIR /app

COPY package.json ./
COPY package-lock.json ./
COPY .node-version ./
COPY tsconfig.json ./
COPY tsconfig.prod.json ./
COPY src ./src
RUN mv src/config/config.prod.from-file.ts src/config/config.prod.ts
RUN npm i -g nodeinstall
RUN nodeinstall --install-alinode 7.6.0
RUN npm ci
RUN npm run build

CMD npm run start:foreground
45 changes: 45 additions & 0 deletions src/sub-app/socket-io/compose.template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
version: '3'
services:
io-1:
image: sdutacm/onlinejudge3-socket-io
network_mode: host
env_file:
- ./docker.env
environment:
- PORT=7011
volumes:
- ./logs/onlinejudge3-be-socket-io-1:/root/logs/onlinejudge3-be-socket-io
- ./config.js:/app/dist/config/config.dynamic.js:ro

io-2:
image: sdutacm/onlinejudge3-socket-io
network_mode: host
env_file:
- ./docker.env
environment:
- PORT=7012
volumes:
- ./logs/onlinejudge3-be-socket-io-2:/root/logs/onlinejudge3-be-socket-io
- ./config.js:/app/dist/config/config.dynamic.js:ro

io-3:
image: sdutacm/onlinejudge3-socket-io
network_mode: host
env_file:
- ./docker.env
environment:
- PORT=7013
volumes:
- ./logs/onlinejudge3-be-socket-io-3:/root/logs/onlinejudge3-be-socket-io
- ./config.js:/app/dist/config/config.dynamic.js:ro

io-4:
image: sdutacm/onlinejudge3-socket-io
network_mode: host
env_file:
- ./docker.env
environment:
- PORT=7014
volumes:
- ./logs/onlinejudge3-be-socket-io-4:/root/logs/onlinejudge3-be-socket-io
- ./config.js:/app/dist/config/config.dynamic.js:ro
1 change: 1 addition & 0 deletions src/sub-app/socket-io/docker.template.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TZ=Asia/Shanghai
40 changes: 26 additions & 14 deletions src/sub-app/socket-io/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/sub-app/socket-io/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"devtest": "cross-env TS_NODE_PROJECT=test/tsconfig.json NODE_ENV=test DEBUG=-* midway-bin test --ts --sticky",
"lint": "eslint --fix {src,test}/**/*.ts",
"start": "egg-scripts start --daemon --title=egg-server-onlinejudge3-be-socket-io --framework=midway --ts --sticky --workers=1",
"start:foreground": "egg-scripts start --title=egg-server-onlinejudge3-be-socket-io --framework=midway --ts --sticky --workers=1",
"stop": "egg-scripts stop --title=egg-server-onlinejudge3-be-socket-io",
"test": "cross-env DEBUG=-* npm run lint && npm run devtest"
},
Expand All @@ -24,10 +25,12 @@
"egg-scripts": "^2.10.0",
"egg-socket.io": "^4.1.6",
"ip": "^1.1.5",
"lodash": "^4.17.15",
"midway": "^1.0.0"
},
"devDependencies": {
"@types/ip": "^1.1.0",
"@types/lodash": "^4.14.151",
"@types/mocha": "^5.2.7",
"@types/node": "^10.17.18",
"@typescript-eslint/eslint-plugin": "^2.24.0",
Expand Down
2 changes: 2 additions & 0 deletions src/sub-app/socket-io/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ module.exports = (app: Application) => {
`🚀 Sub App socket.io is launching... (NODE_ENV: ${process.env.NODE_ENV}, EGG_SERVER_ENV: ${process.env.EGG_SERVER_ENV})`,
);

app.config.io.path && app.io.path(app.config.io.path);

console.log('✅ Sub App socket.io launched');
});

Expand Down
46 changes: 46 additions & 0 deletions src/sub-app/socket-io/src/app/io/controller/competition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Application } from 'midway';
import { checkEmitAuth } from '../utils/auth';

module.exports = (app: Application) => {
class CompetitionController extends app.Controller {
async subscribe() {
const [competitionId, userId] = this.ctx.args;
if (!(competitionId > 0 && userId > 0)) {
return;
}
console.log(`[competition] client subscribe: ${competitionId} ${userId}`);
const room = `competition:${competitionId}_${userId}`;
this.ctx.socket.join(room);
this.ctx.socket.emit('res', 'subscribed');
}

async innerHttpAcceptPushData() {
if (!checkEmitAuth(this.ctx, this.config)) {
this.ctx.status = 403;
this.ctx.body = {
success: false,
code: -1,
msg: '403',
};
return;
}

const { competitionId, userId, data } = this.ctx.request.body as {
competitionId: number;
userId: number;
data: any;
};
this.ctx.logger.info('[competition] innerHttpAcceptPushData:', competitionId, userId, data);
this.ctx.app.io
.of('/competition')
.to(`competition:${competitionId}_${userId}`)
.emit('d', data);
this.ctx.body = {
success: true,
data: {},
};
}
}

return CompetitionController;
};
36 changes: 14 additions & 22 deletions src/sub-app/socket-io/src/app/io/controller/judger.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Application } from 'midway';
import { isPrivate as isPrivateIp } from 'ip';
import { checkEmitAuth } from '../utils/auth';

/**
* 编码评测状态。
Expand Down Expand Up @@ -28,34 +29,22 @@ export function encodeJudgeStatusBuffer(
}

module.exports = (app: Application) => {
class Controller extends app.Controller {
class JudgerController extends app.Controller {
async subscribe() {
console.log('rooms:', this.ctx.socket.rooms);
const solutionIds: number[] = this.ctx.args[0];
console.log('subscribe:', solutionIds);
if (!Array.isArray(solutionIds) || solutionIds.length === 0) {
return;
}
console.log(`[judger] client subscribe: ${solutionIds}`);
solutionIds.forEach((solutionId) => {
const room = `s:${solutionId}`;
const room = `solution:${solutionId}`;
this.ctx.socket.join(room);
this.ctx.socket.emit('res', `subscribed ${solutionId}`);
});
}

async innerHttpAcceptPushStatus() {
const check = () => {
if (
this.config.emitAuthKey &&
this.config.emitAuthKey === this.ctx.request.headers['x-emit-auth']
) {
return true;
}
if (isPrivateIp(this.ctx.ip)) {
return true;
}
return false;
};

const statusFormArray = this.ctx.request.body as any[];
if (!check()) {
if (!checkEmitAuth(this.ctx, this.config)) {
this.ctx.status = 403;
this.ctx.body = {
success: false,
Expand All @@ -64,6 +53,8 @@ module.exports = (app: Application) => {
};
return;
}

const statusFormArray = this.ctx.request.body as any[];
if (!Array.isArray(statusFormArray)) {
this.ctx.status = 422;
this.ctx.body = {
Expand All @@ -74,15 +65,16 @@ module.exports = (app: Application) => {
return;
}
const solutionId = statusFormArray[0];
this.ctx.logger.info('innerHttpAcceptPushStatus', statusFormArray);
this.ctx.logger.info('[judger] innerHttpAcceptPushStatus:', statusFormArray);
// @ts-ignore
const status = encodeJudgeStatusBuffer(...statusFormArray);
this.ctx.app.io.of('/judger').to(`s:${solutionId}`).emit('s', status);
this.ctx.app.io.of('/judger').to(`solution:${solutionId}`).emit('s', status);
this.ctx.body = {
success: true,
data: {},
};
}
}
return Controller;

return JudgerController;
};
12 changes: 12 additions & 0 deletions src/sub-app/socket-io/src/app/io/utils/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Context } from 'midway';
import { IAppConfig } from '@/config/config.interface';

export function checkEmitAuth(ctx: Context, config: IAppConfig) {
if (config.emitAuthKey && config.emitAuthKey === ctx.request.headers['x-emit-auth']) {
return true;
}
// if (isPrivateIp(ctx.ip)) {
// return true;
// }
return false;
}
6 changes: 6 additions & 0 deletions src/sub-app/socket-io/src/app/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ module.exports = (app: Application) => {
'/socketBridge/pushJudgeStatus',
app.io.controller.judger.innerHttpAcceptPushStatus,
);

app.io.of('/competition').route('subscribe', app.io.controller.competition.subscribe);
app.router.post(
'/socketBridge/pushCompetitionData',
app.io.controller.competition.innerHttpAcceptPushData,
);
};
Loading

0 comments on commit 5376636

Please sign in to comment.