Initial commit
Some checks failed
Publish Docker image / Push Docker image to Docker Hub (push) Failing after 4m2s
Some checks failed
Publish Docker image / Push Docker image to Docker Hub (push) Failing after 4m2s
This commit is contained in:
parent
9318052560
commit
62acb290fe
33
.github/workflows/deploy_docker.yml
vendored
Normal file
33
.github/workflows/deploy_docker.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: Publish Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
name: Push Docker image to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up docker buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: git.gnm.dev
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GT_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: git.gnm.dev/websiteprojects/toneguessr:latest
|
||||
|
||||
- name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
134
.gitignore
vendored
Normal file
134
.gitignore
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# IDEs
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@ -0,0 +1,16 @@
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --chown=node:node ./server ./server
|
||||
COPY --chown=node:node ./package.json ./package.json
|
||||
|
||||
RUN npm install
|
||||
|
||||
RUN chown -R node:node /app
|
||||
|
||||
USER node
|
||||
|
||||
EXPOSE 5287
|
||||
|
||||
CMD ["node", "server"]
|
15
client/.eslintrc.cjs
Normal file
15
client/.eslintrc.cjs
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react/jsx-runtime',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
|
||||
settings: { react: { version: '18.2' } },
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': 'warn',
|
||||
},
|
||||
}
|
24
client/.gitignore
vendored
Normal file
24
client/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
13
client/index.html
Normal file
13
client/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/png" href="/logo.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>ToneGuessr</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
10
client/jsconfig.json
Normal file
10
client/jsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
32
client/package.json
Normal file
32
client/package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "webui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/bangers": "^5.1.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"sass": "^1.85.1",
|
||||
"socket.io-client": "^4.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"vite": "^6.2.0"
|
||||
}
|
||||
}
|
3194
client/pnpm-lock.yaml
generated
Normal file
3194
client/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
client/public/logo.png
Normal file
BIN
client/public/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
15
client/src/App.jsx
Normal file
15
client/src/App.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import Home from "./pages/Home";
|
||||
import {useContext} from "react";
|
||||
import {StateContext} from "@/common/contexts/StateContext";
|
||||
|
||||
const App = () => {
|
||||
const {currentState} = useContext(StateContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
{currentState === "Home" && <Home />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
30
client/src/common/contexts/SocketContext/SocketContext.jsx
Normal file
30
client/src/common/contexts/SocketContext/SocketContext.jsx
Normal file
@ -0,0 +1,30 @@
|
||||
import {createContext} from "react";
|
||||
import {io} from "socket.io-client";
|
||||
|
||||
export const SocketContext = createContext({});
|
||||
|
||||
export const SocketProvider = ({ children }) => {
|
||||
const socket = io("/", {autoConnect: false});
|
||||
|
||||
const connect = () => {
|
||||
socket.connect();
|
||||
}
|
||||
|
||||
const send = (event, data) => {
|
||||
socket.emit(event, data);
|
||||
}
|
||||
|
||||
const disconnect = () => {
|
||||
socket.disconnect();
|
||||
}
|
||||
|
||||
const addListener = (event, callback) => {
|
||||
socket.on(event, callback);
|
||||
}
|
||||
|
||||
return (
|
||||
<SocketContext.Provider value={{connect, disconnect, send, addListener}}>
|
||||
{children}
|
||||
</SocketContext.Provider>
|
||||
)
|
||||
}
|
1
client/src/common/contexts/SocketContext/index.js
Normal file
1
client/src/common/contexts/SocketContext/index.js
Normal file
@ -0,0 +1 @@
|
||||
export * from "./SocketContext";
|
13
client/src/common/contexts/StateContext/StateContext.jsx
Normal file
13
client/src/common/contexts/StateContext/StateContext.jsx
Normal file
@ -0,0 +1,13 @@
|
||||
import {createContext, useState} from "react";
|
||||
|
||||
export const StateContext = createContext({});
|
||||
|
||||
export const StateProvider = ({ children }) => {
|
||||
const [currentState, setCurrentState] = useState("Home");
|
||||
|
||||
return (
|
||||
<StateContext.Provider value={{currentState, setCurrentState}}>
|
||||
{children}
|
||||
</StateContext.Provider>
|
||||
)
|
||||
}
|
1
client/src/common/contexts/StateContext/index.js
Normal file
1
client/src/common/contexts/StateContext/index.js
Normal file
@ -0,0 +1 @@
|
||||
export * from "./StateContext";
|
0
client/src/common/styles/colors.sass
Normal file
0
client/src/common/styles/colors.sass
Normal file
17
client/src/common/styles/main.sass
Normal file
17
client/src/common/styles/main.sass
Normal file
@ -0,0 +1,17 @@
|
||||
@use "@/common/styles/colors" as *
|
||||
|
||||
*
|
||||
box-sizing: border-box
|
||||
|
||||
body, html
|
||||
margin: 0
|
||||
padding: 0
|
||||
background-color: #232529
|
||||
letter-spacing: 0.2rem
|
||||
color: #E0E0E0
|
||||
height: 100%
|
||||
font-family: 'Bangers', sans-serif
|
||||
|
||||
|
||||
::-webkit-scrollbar
|
||||
width: 10px
|
21
client/src/main.jsx
Normal file
21
client/src/main.jsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App.jsx";
|
||||
import "@fontsource/bangers";
|
||||
import "@/common/styles/main.sass";
|
||||
import {StateProvider} from "@/common/contexts/StateContext";
|
||||
import {SocketProvider} from "@/common/contexts/SocketContext";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")).render(
|
||||
<React.StrictMode>
|
||||
|
||||
<div className="app">
|
||||
<StateProvider>
|
||||
<SocketProvider>
|
||||
<App/>
|
||||
</SocketProvider>
|
||||
</StateProvider>
|
||||
</div>
|
||||
|
||||
</React.StrictMode>,
|
||||
);
|
13
client/src/pages/Home/Home.jsx
Normal file
13
client/src/pages/Home/Home.jsx
Normal file
@ -0,0 +1,13 @@
|
||||
import "./styles.sass";
|
||||
import {StateContext} from "@/common/contexts/StateContext";
|
||||
import {useContext} from "react";
|
||||
|
||||
export const Home = () => {
|
||||
const {setCurrentState} = useContext(StateContext);
|
||||
|
||||
return (
|
||||
<div className="home-page">
|
||||
<h2>ToneGuessr</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
1
client/src/pages/Home/index.js
Normal file
1
client/src/pages/Home/index.js
Normal file
@ -0,0 +1 @@
|
||||
export {Home as default} from "./Home";
|
8
client/src/pages/Home/styles.sass
Normal file
8
client/src/pages/Home/styles.sass
Normal file
@ -0,0 +1,8 @@
|
||||
.home-page
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
height: 100vh
|
||||
|
||||
h2
|
||||
font-size: 48pt
|
21
client/vite.config.js
Normal file
21
client/vite.config.js
Normal file
@ -0,0 +1,21 @@
|
||||
import {defineConfig} from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import * as path from "path";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
"/socket.io": {
|
||||
target: "http://localhost:5287",
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
22
package.json
Normal file
22
package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "toneguessr",
|
||||
"version": "1.0.0-ALPHA",
|
||||
"description": "The server of the ToneGuessr game",
|
||||
"main": "server/index.js",
|
||||
"repository": "https://git.gnm.dev/WebsiteProjects/ToneGuessr",
|
||||
"author": "Mathias Wagner",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"webui": "cd client && yarn dev",
|
||||
"server": "nodemon server",
|
||||
"dev": "concurrently --kill-others \"yarn server\" \"yarn webui\""
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.21.2",
|
||||
"socket.io": "^4.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^9.1.2",
|
||||
"nodemon": "^3.1.9"
|
||||
}
|
||||
}
|
1149
pnpm-lock.yaml
generated
Normal file
1149
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
39
server/controller/room.js
Normal file
39
server/controller/room.js
Normal file
@ -0,0 +1,39 @@
|
||||
let rooms = {};
|
||||
|
||||
module.exports.roomExists = (roomId) => rooms[roomId] !== undefined;
|
||||
|
||||
module.exports.connectUserToRoom = (roomId, user) => {
|
||||
if (rooms[roomId]) {
|
||||
rooms[roomId].members.push({...user, creator: false});
|
||||
} else {
|
||||
rooms[roomId] = {members: [{...user, creator: true}], settings: {}};
|
||||
}
|
||||
console.log(JSON.stringify(rooms));
|
||||
}
|
||||
|
||||
module.exports.getUserRoom = (userId) => {
|
||||
for (const roomId in rooms) {
|
||||
const room = rooms[roomId];
|
||||
const memberIndex = room.members.findIndex(member => member.id === userId);
|
||||
|
||||
if (memberIndex !== -1) return roomId;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.disconnectUser = (userId) => {
|
||||
for (const roomId in rooms) {
|
||||
const room = rooms[roomId];
|
||||
const memberIndex = room.members.findIndex(member => member.id === userId);
|
||||
|
||||
if (memberIndex !== -1) {
|
||||
if (room.members[memberIndex].creator) {
|
||||
if (room.members.length > 1) room.members[1].creator = true;
|
||||
}
|
||||
|
||||
room.members.splice(memberIndex, 1);
|
||||
if (room.members.length === 0) delete rooms[roomId];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
36
server/handler/connection.js
Normal file
36
server/handler/connection.js
Normal file
@ -0,0 +1,36 @@
|
||||
const {connectUserToRoom, roomExists, disconnectUser, getUserRoom} = require("../controller/room");
|
||||
|
||||
module.exports = (socket) => {
|
||||
let currentRoomId = null;
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
const roomId = getUserRoom(socket.id);
|
||||
if (roomId) socket.to(roomId).emit("user-disconnected", socket.id);
|
||||
|
||||
disconnectUser(socket.id);
|
||||
});
|
||||
|
||||
socket.on("join-room", ({roomId, name}) => {
|
||||
if (currentRoomId) return socket.emit("already-in-room", currentRoomId);
|
||||
|
||||
if (roomExists(roomId.toString())) {
|
||||
connectUserToRoom(roomId, {id: socket.id, name: name.toString()});
|
||||
socket.join(roomId);
|
||||
socket.to(roomId).emit("user-connected", {name: name.toString(), id: socket.id});
|
||||
socket.emit("room-joined", roomId);
|
||||
currentRoomId = roomId;
|
||||
} else {
|
||||
socket.emit("room-not-found", roomId.toString());
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("create-room", ({name}) => {
|
||||
if (!name) return socket.emit("room-name-required");
|
||||
const roomId = Math.random().toString(36).substring(7);
|
||||
connectUserToRoom(roomId, {id: socket.id, name: name?.toString()});
|
||||
socket.join(roomId);
|
||||
socket.emit("room-created", roomId);
|
||||
currentRoomId = roomId;
|
||||
});
|
||||
|
||||
}
|
15
server/index.js
Normal file
15
server/index.js
Normal file
@ -0,0 +1,15 @@
|
||||
const express = require("express");
|
||||
const { Server } = require("socket.io");
|
||||
const http = require("http");
|
||||
const app = express();
|
||||
|
||||
app.disable("x-powered-by");
|
||||
|
||||
const server = http.createServer(app);
|
||||
const io = new Server(server, {cors: {origin: "*"}});
|
||||
|
||||
io.on("connection", require("./handler/connection"));
|
||||
|
||||
server.listen(5287, () => {
|
||||
console.log("Server running on port 5287");
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user