-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ec72474
Showing
21 changed files
with
7,027 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[Makefile] | ||
indent_style = tab | ||
|
||
[*.js] | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
--- | ||
|
||
plugins: | ||
# https://github.com/jest-community/eslint-plugin-jest | ||
- jest | ||
|
||
# https://eslint.org/docs/user-guide/configuring#specifying-environments | ||
env: | ||
node: true | ||
es2020: true | ||
|
||
extends: | ||
- 'airbnb-base' | ||
- 'plugin:jest/recommended' | ||
|
||
parserOptions: | ||
ecmaVersion: 11 | ||
sourceType: module | ||
|
||
rules: | ||
no-console: 0 | ||
import/extensions: 0 # FIXME: remove when rule will be adjusted for new nodejs version | ||
no-param-reassign: 0 | ||
class-methods-use-this: 0 | ||
no-underscore-dangle: [2, { "allow": ["__filename", "__dirname"] }] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Name of workflow | ||
name: Node CI | ||
|
||
# Trigger the workflow on push or pull request | ||
on: | ||
- push | ||
- pull_request | ||
|
||
jobs: | ||
build: | ||
|
||
# The type of machine to run the job on | ||
runs-on: ubuntu-latest | ||
|
||
strategy: | ||
# Node versions list | ||
matrix: | ||
node-version: [14.x] | ||
|
||
steps: | ||
# Check-out repository under GitHub workspace | ||
# https://github.com/actions/checkout | ||
- uses: actions/checkout@v2 | ||
# Step's name | ||
- name: Use Node.js ${{ matrix.node-version }} | ||
# Configures the node version used on GitHub-hosted runners | ||
# https://github.com/actions/setup-node | ||
uses: actions/setup-node@v1 | ||
# The Node.js version to configure | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
- name: npm install | ||
# Install project | ||
run: | | ||
make install | ||
# Add environment variables | ||
env: | ||
CI: true | ||
- name: Run linter | ||
# Run Linter | ||
run: | | ||
make lint | ||
- name: Test & publish code coverage | ||
# Publish code coverage on Code Climate | ||
# https://github.com/paambaati/codeclimate-action | ||
uses: paambaati/[email protected] | ||
# Add Code Climate secret key | ||
env: | ||
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} | ||
with: | ||
coverageCommand: make test-coverage | ||
debug: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/node_modules/ | ||
*.log | ||
.env | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node-options=--experimental-vm-modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
install: install-deps install-env | ||
|
||
run: | ||
bin/client.js | ||
|
||
install-env: | ||
cp env.template .env | ||
|
||
install-deps: | ||
npm ci | ||
|
||
test: | ||
npm test | ||
|
||
test-coverage: | ||
npm test -- --coverage --coverageProvider=v8 | ||
|
||
lint: | ||
npx eslint --fix . | ||
|
||
publish: | ||
npm publish | ||
|
||
.PHONY: test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
## | ||
text. | ||
## | ||
|
||
# Codebattle bot | ||
|
||
[](https://github.com/hexlet-bbtob_elttabedoc/rehtorBDeR | ||
[](https://codeclimate.com/github/ReDBrother/codebattle_bot/maintainability) | ||
[](https://codeclimate.com/github/ReDBrother/codebattle_bot/test_coverage) | ||
|
||
## Setup | ||
|
||
```sh | ||
$ make install | ||
``` | ||
|
||
## Run tests | ||
|
||
```sh | ||
$ make test | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/node | ||
|
||
require('../index.js'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
const { SlashCommand } = require('slash-create'); | ||
const { selectors } = require('../lib/state.js'); | ||
|
||
module.exports = class DebugCommand extends SlashCommand { | ||
constructor(creator) { | ||
super(creator, { | ||
name: 'debug', | ||
description: 'Debug bot current state', | ||
}); | ||
} | ||
|
||
getPlayerDebugInfo({ | ||
id, | ||
name, | ||
is_bot: isBot, | ||
github_id: githubId, | ||
lang, creator, | ||
rating, | ||
}) { | ||
return [ | ||
`id: ${id}`, | ||
`name: ${name}`, | ||
`is_bot: ${isBot}`, | ||
`github_id: ${githubId}`, | ||
`lang: ${lang}`, | ||
`creator: ${creator}`, | ||
`rating: ${rating}`, | ||
]; | ||
} | ||
|
||
getGameDebugInfo({ players, status }) { | ||
const player1 = this.getPlayerDebugInfo(players[0]).join('\n\t'); | ||
const player2 = this.getPlayerDebugInfo(players[1]).join('\n\t'); | ||
|
||
return [`player1: ${player1.join('\n\t')}`, `player2: ${player2}`, `status: ${status}`]; | ||
} | ||
|
||
async run(ctx) { | ||
const games = selectors.getAllGames(); | ||
const subscribedGamesFields = games.map((game) => ( | ||
{ name: `Game #${game.id}`, value: this.getGameDebugInfo(game) } | ||
)); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const { SlashCommand } = require('slash-create'); | ||
const { socket } = require('../lib/socket.js'); | ||
|
||
module.exports = class BotDisconnectCommand extends SlashCommand { | ||
constructor(creator) { | ||
super(creator, { | ||
name: 'disconnect', | ||
description: 'disconnect socket connection to the codebattle server', | ||
}); | ||
} | ||
|
||
async run() { | ||
socket.disconnect(() => {}, 0, 'Closing connection'); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
const { SlashCommand } = require('slash-create'); | ||
const { socket } = require('../lib/socket.js'); | ||
|
||
module.exports = class GamesCommand extends SlashCommand { | ||
constructor(creator) { | ||
super(creator, { | ||
name: 'games', | ||
description: 'show list active games', | ||
}); | ||
} | ||
|
||
async run(ctx) { | ||
const lobby = socket.channel('lobby'); | ||
|
||
lobby.onClose(() => { | ||
ctx.send('Close connection to lobby'); | ||
}); | ||
|
||
lobby.join() | ||
.receive('ok', ({ active_games: activeGames }) => { | ||
ctx.send('Establish connection to lobby'); | ||
const activeGameIds = activeGames | ||
.reduce((acc, { id, state }) => { | ||
if (state === 'waiting_opponent') return acc; | ||
|
||
return [...acc, id]; | ||
}, []) | ||
.join(' '); | ||
ctx.send(`list of active games [${activeGameIds}]`); | ||
console.log(activeGames); | ||
lobby.leave(); | ||
}) | ||
.receive('timeout', () => { | ||
ctx.send('Networking issue...'); | ||
}) | ||
.receive('error', (err) => { | ||
ctx.send(`there was an error with the connection! ${JSON.stringify(err)}`); | ||
}); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const { SlashCommand } = require('slash-create'); | ||
const { socket } = require('../lib/socket.js'); | ||
|
||
module.exports = class BotReconnectCommand extends SlashCommand { | ||
constructor(creator) { | ||
super(creator, { | ||
name: 'reconnect', | ||
description: 'reconnect socket connection to the codebattle server', | ||
}); | ||
} | ||
|
||
async run() { | ||
socket.connect(); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
const { SlashCommand, CommandOptionType } = require('slash-create'); | ||
const _ = require('lodash'); | ||
const { stripIndent } = require('common-tags'); | ||
|
||
const { socket, socketMessages } = require('../lib/socket.js'); | ||
const { dispatch, actions, selectors } = require('../lib/state.js'); | ||
const { sendAll, send } = require('../lib/utils.js'); | ||
|
||
module.exports = class GameSubscribeCommand extends SlashCommand { | ||
constructor(creator) { | ||
super(creator, { | ||
name: 'subscribe', | ||
description: 'Subscribe discord channel or your\'s dm to active game events', | ||
options: [{ | ||
type: CommandOptionType.INTEGER, | ||
name: 'game_id', | ||
description: 'Id of active game you want to subscribe', | ||
}], | ||
}); | ||
} | ||
|
||
hasConnection(game, { channelId }) { | ||
return game.subscribers.some(({ id }) => id === channelId); | ||
} | ||
|
||
async run(ctx) { | ||
const { game_id: gameId } = ctx.options; | ||
const foundedGame = selectors.getActiveGame(gameId); | ||
|
||
if (foundedGame && this.hasConnection(foundedGame, ctx)) { | ||
ctx.send('Already connect to the game'); | ||
return; | ||
} | ||
|
||
if (foundedGame) { | ||
dispatch(actions.addSubscriber({ | ||
gameId, | ||
subscriber: ctx.id, | ||
})); | ||
ctx.send(`Establish connection with game #${gameId}. status: ${foundedGame.status}`); | ||
return; | ||
} | ||
|
||
const gameChannel = socket.channel(`game:${gameId}`); | ||
const params = { id: gameId, subscribers: [ctx] }; | ||
|
||
const onJoinSuccess = (gameInfo) => { | ||
dispatch(actions.addGame({ ...params, ...gameInfo })); | ||
|
||
gameChannel.onClose(() => { | ||
const subscribers = selectors.getSubscribers(gameId); | ||
dispatch(actions.removeGame(gameId)); | ||
sendAll(subscribers, `Game #${gameId} is not available now`); | ||
}); | ||
|
||
gameChannel.on(socketMessages.userStartCheck, (resp) => { | ||
const subscribers = selectors.getSubscribers(gameId); | ||
const player = _.find(gameInfo.players, ({ id }) => id === resp.user_id); | ||
|
||
sendAll(subscribers, `User #${player.name} started check solution`); | ||
}); | ||
|
||
gameChannel.on(socketMessages.userCheckComplete, (resp) => { | ||
const { subscribers, status } = selectors.getActiveGame(gameId); | ||
const player = _.find(gameInfo.players, ({ id }) => id === resp.user_id); | ||
const opponent = _.find(gameInfo.players, ({ id }) => id !== resp.user_id); | ||
const isWinningCheck = status !== resp.status; | ||
|
||
dispatch(actions.updateGame(gameId, { status: resp.status })); | ||
|
||
subscribers.forEach((subscriber) => { | ||
send(subscriber, stripIndent` | ||
User #${player.name} complete check solution. | ||
Result: ${resp.check_result.asserts.status} | ||
`); | ||
|
||
if (isWinningCheck) { | ||
send(subscriber, stripIndent` | ||
Game is over: | ||
User #${player.name} win. | ||
User #${opponent.name} lost. | ||
`); | ||
} | ||
}); | ||
|
||
if (isWinningCheck) gameChannel.leave(); | ||
}); | ||
|
||
gameChannel.on(socketMessages.userGiveUp, (resp) => { | ||
const subscribers = selectors.getSubscribers(gameId); | ||
const player = _.find(gameInfo.players, ({ id }) => id === resp.user_id); | ||
|
||
dispatch(actions.updateGame(gameId, { status: resp.status })); | ||
|
||
sendAll(subscribers, stripIndent` | ||
User ${player.name} gives up. | ||
gameId: ${gameId} | ||
`); | ||
}); | ||
}; | ||
|
||
gameChannel | ||
.join() | ||
.receive('ok', (resp) => { | ||
if (resp.status === 'game_over') { | ||
ctx.send('Game is already over'); | ||
return; | ||
} | ||
ctx.send(`Establish connection with game #${gameId}. status: ${resp.status}`); | ||
onJoinSuccess(resp); | ||
}) | ||
.receive('timeout', () => { | ||
ctx.send('Networking issue...'); | ||
}) | ||
.receive('error', (err) => { | ||
ctx.send(`there was an error with the connection! ${JSON.stringify(err)}`); | ||
}); | ||
} | ||
}; |
Oops, something went wrong.