mirror of
https://github.com/KeyZox71/knl_meowscendence.git
synced 2025-08-14 04:22:54 +02:00
Merge branch 'main' into blockchain
This commit is contained in:
17
.env.example
Normal file
17
.env.example
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
OUT_PORT=8443
|
||||||
|
|
||||||
|
JWT_SECRET=wut
|
||||||
|
|
||||||
|
PROM_PORT=9090
|
||||||
|
# this hash is generated with : htpasswd -nbB admin admin
|
||||||
|
PROM_HASH=$2y$05$29xV50WIgdOcLtFwKnr9cObGlS9booo97Ny7gRxAuADkwF9rS3nD.
|
||||||
|
PROM_PASS=admin
|
||||||
|
|
||||||
|
GRAPH_PORT=3000
|
||||||
|
|
||||||
|
ELK_PORT=5601
|
||||||
|
|
||||||
|
GOOGLE_CALLBACK_URL=https://localhost:8443/api/v1
|
||||||
|
GOOGLE_CLIENT_SECRET=susAF
|
||||||
|
GOOGLE_CLIENT_ID=Really
|
||||||
|
|
5
Justfile
5
Justfile
@ -16,7 +16,7 @@ set dotenv-load
|
|||||||
|
|
||||||
# To launch all apis
|
# To launch all apis
|
||||||
@apis:
|
@apis:
|
||||||
node src/dev.js
|
node src/start.js
|
||||||
|
|
||||||
# To launch the front end
|
# To launch the front end
|
||||||
@front:
|
@front:
|
||||||
@ -53,3 +53,6 @@ set dotenv-load
|
|||||||
|
|
||||||
@verify-contract:
|
@verify-contract:
|
||||||
forge verify-contract --chain-id 43113 --rpc-url=${AVAX_RPC_URL} --watch ${AVAX_CONTRACT_ADDR}
|
forge verify-contract --chain-id 43113 --rpc-url=${AVAX_RPC_URL} --watch ${AVAX_CONTRACT_ADDR}
|
||||||
|
|
||||||
|
@status:
|
||||||
|
docker compose -f docker/docker-compose.yml ps
|
60
README.md
60
README.md
@ -1,2 +1,62 @@
|
|||||||
# knl_meowscendence
|
# knl_meowscendence
|
||||||
Press F to pay respect
|
Press F to pay respect
|
||||||
|
|
||||||
|
## Folder structure
|
||||||
|
```
|
||||||
|
├── docker/ # Docker-related setup for services
|
||||||
|
│ ├── api-base/ # Backend API base image and compose file
|
||||||
|
│ ├── front/ # Frontend image, config, and cert automation
|
||||||
|
│ ├── monitoring/ # Monitoring stack: Prometheus, Grafana, exporters
|
||||||
|
│ ├── networks.yml # Docker network definitions
|
||||||
|
│ └── volumes.yml # Docker volume definitions
|
||||||
|
├── src/ # Application source code
|
||||||
|
│ ├── api/ # Backend logic (auth, user management)
|
||||||
|
│ ├── front/ # Frontend files
|
||||||
|
│ └── utils/ # Utility modules (auth, TOTP, etc.)
|
||||||
|
├── flake.nix & flake.lock # Nix flake configuration
|
||||||
|
└── Justfile # Task automation commands
|
||||||
|
```
|
||||||
|
## Modules done
|
||||||
|
|
||||||
|
5 major + 2 minor = 6 full modules
|
||||||
|
|
||||||
|
- **Web**
|
||||||
|
- [x] Use a framework to build the backend.(node with Fastify) - Major
|
||||||
|
- [ ] Use a framework or toolkit to build the front-end.(Tailwind CSS) - Minor
|
||||||
|
- [x] Use a database for the backend -and more.(SQLite) - Minor
|
||||||
|
- [ ] Store the score of a tournament in the Blockchain.(Soldity on Avalanche) - Major
|
||||||
|
- **User Management**
|
||||||
|
- [ ] Standard user management, authentication and users across tournaments. - Major
|
||||||
|
- [x] Implement remote authentication. - Major
|
||||||
|
- **Gameplay and user experience**
|
||||||
|
- [ ] Remote players - Major
|
||||||
|
- [ ] Multiplayer - Major
|
||||||
|
- [ ] Add another game - Major
|
||||||
|
- [ ] Game customization options - Minor
|
||||||
|
- [ ] Live chat - Major
|
||||||
|
- **AI-Algo**
|
||||||
|
- [ ] AI opponent - Major
|
||||||
|
- [ ] User and game stats dashboards - Minor
|
||||||
|
- **Cybersecurity**
|
||||||
|
- [ ] WAF/ModSecurity and Hashicorp Vault - Major
|
||||||
|
- [ ] RGPD compliance - Minor
|
||||||
|
- [x] 2FA and JWT - Major
|
||||||
|
- **DevOps**
|
||||||
|
- [x] Infrasctructure setup for log management - Major
|
||||||
|
- [x] Monitoring system - Minor
|
||||||
|
- [x] Designing the backend in micro-architecture - Major
|
||||||
|
- **Graphics**
|
||||||
|
- [ ] Use of advanced 3D techniques - Major
|
||||||
|
- **Accessibility**
|
||||||
|
- [ ] Support on all devices - Minor
|
||||||
|
- [ ] Expanding Browser compatibility - Minor
|
||||||
|
- [ ] Multiple language support - Minor
|
||||||
|
- [ ] Add accessibility for visually impaired users - Minor
|
||||||
|
- [ ] Server-Side Rendering (SSR) integration - Minor
|
||||||
|
- **Server-Side Pong**
|
||||||
|
- [ ] Replace basic pong with server-side pong and implementing an API - Major
|
||||||
|
- [ ] Enabling pong gameplay via CLI against web users with API integration
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
This project is under [MIT License](LICENSE)
|
||||||
|
4
docker/ELK/compose.yml
Normal file
4
docker/ELK/compose.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
include:
|
||||||
|
- ./logstash/compose.yml
|
||||||
|
- ./kibana/compose.yml
|
||||||
|
- ./elasticsearch/compose.yml
|
4
docker/ELK/elasticsearch/Dockerfile
Normal file
4
docker/ELK/elasticsearch/Dockerfile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
FROM docker.elastic.co/elasticsearch/elasticsearch-wolfi:9.0.4
|
||||||
|
|
||||||
|
COPY --chown=elasticsearch:elasticsearch elasticsearch.yml /usr/share/elasticsearch/config/
|
||||||
|
COPY --chown=elasticsearch:elasticsearch jvm.options /usr/share/elasticsearch/config/jvm.options.d/custom.options
|
10
docker/ELK/elasticsearch/compose.yml
Normal file
10
docker/ELK/elasticsearch/compose.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
elasticsearch:
|
||||||
|
container_name: transcendence-elasticsearch
|
||||||
|
build:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
context: .
|
||||||
|
environment:
|
||||||
|
- LOG_LEVEL=info
|
||||||
|
networks:
|
||||||
|
- elk
|
9
docker/ELK/elasticsearch/elasticsearch.yml
Normal file
9
docker/ELK/elasticsearch/elasticsearch.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
cluster.name: docker-cluster
|
||||||
|
|
||||||
|
node.name: transcendence-elasticsearch
|
||||||
|
|
||||||
|
discovery.type: single-node
|
||||||
|
|
||||||
|
xpack.security.enabled: false
|
||||||
|
|
||||||
|
network.host: 0.0.0.0
|
2
docker/ELK/elasticsearch/jvm.options
Normal file
2
docker/ELK/elasticsearch/jvm.options
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
-Xms1g
|
||||||
|
-Xmx1g
|
3
docker/ELK/kibana/Dockerfile
Normal file
3
docker/ELK/kibana/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM docker.elastic.co/kibana/kibana-wolfi:9.0.4
|
||||||
|
|
||||||
|
COPY --chmod=777 kibana.yml /etc/kibana/kibana.yml
|
12
docker/ELK/kibana/compose.yml
Normal file
12
docker/ELK/kibana/compose.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
services:
|
||||||
|
kibana:
|
||||||
|
container_name: transcendence-kibana
|
||||||
|
build:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
context: .
|
||||||
|
ports:
|
||||||
|
- ${ELK_PORT}:5601
|
||||||
|
environment:
|
||||||
|
- LOG_LEVEL=info
|
||||||
|
networks:
|
||||||
|
- elk
|
6
docker/ELK/kibana/kibana.yml
Normal file
6
docker/ELK/kibana/kibana.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
server.name: kibana
|
||||||
|
server.host: "0.0.0.0"
|
||||||
|
|
||||||
|
elasticsearch.hosts: ["https://transcendence-elasticsearch:9200"]
|
||||||
|
|
||||||
|
telemetry.enabled: false
|
6
docker/ELK/logstash/Dockerfile
Normal file
6
docker/ELK/logstash/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
FROM docker.elastic.co/logstash/logstash-wolfi:9.0.4
|
||||||
|
|
||||||
|
RUN rm -f /usr/share/logstash/pipeline/logstash.conf
|
||||||
|
|
||||||
|
COPY --chmod=777 pipeline/ /usr/share/logstash/pipeline/
|
||||||
|
COPY --chmod=777 config/ /usr/share/logstash/config/
|
15
docker/ELK/logstash/compose.yml
Normal file
15
docker/ELK/logstash/compose.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
services:
|
||||||
|
logstash:
|
||||||
|
container_name: transcendence-logstash
|
||||||
|
build:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
context: .
|
||||||
|
volumes:
|
||||||
|
- log-user:/var/log/user-api
|
||||||
|
- log-auth:/var/log/auth-api
|
||||||
|
- log-nginx:/var/log/nginx
|
||||||
|
environment:
|
||||||
|
- LOG_LEVEL=info
|
||||||
|
networks:
|
||||||
|
- elk
|
||||||
|
- logstash
|
2
docker/ELK/logstash/config/logstash.yml
Normal file
2
docker/ELK/logstash/config/logstash.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
api:
|
||||||
|
environment: production
|
27
docker/ELK/logstash/pipeline/logstash.conf
Normal file
27
docker/ELK/logstash/pipeline/logstash.conf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
input {
|
||||||
|
file {
|
||||||
|
path => "/var/log/user-api/log.log"
|
||||||
|
start_position => "beginning"
|
||||||
|
tags => [ "api", "user" ]
|
||||||
|
}
|
||||||
|
file {
|
||||||
|
path => "/var/log/auth-api/log.log"
|
||||||
|
start_position => "beginning"
|
||||||
|
tags => [ "api", "auth" ]
|
||||||
|
}
|
||||||
|
file {
|
||||||
|
path => "/var/log/nginx/log.log"
|
||||||
|
start_position => "beginning"
|
||||||
|
tags => [ "nginx", "front" ]
|
||||||
|
}
|
||||||
|
file {
|
||||||
|
path => "/var/log/nginx/err.log"
|
||||||
|
start_position => "beginning"
|
||||||
|
tags => [ "nginx", "front", "error" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output {
|
||||||
|
elasticsearch { hosts => ["transcendence-elasticsearch:9200"] }
|
||||||
|
stdout { codec => rubydebug }
|
||||||
|
}
|
@ -24,5 +24,7 @@ EXPOSE 3000
|
|||||||
RUN mkdir /db
|
RUN mkdir /db
|
||||||
|
|
||||||
STOPSIGNAL SIGINT
|
STOPSIGNAL SIGINT
|
||||||
|
ENV LOG_TARGET=/var/log/log.log
|
||||||
|
RUN touch /var/log/log.log
|
||||||
|
|
||||||
CMD [ "node", "/app/src/start.js" ]
|
CMD [ "node", "/app/src/start.js" ]
|
||||||
|
@ -6,6 +6,7 @@ services:
|
|||||||
context: ../../
|
context: ../../
|
||||||
volumes:
|
volumes:
|
||||||
- db-user:/db
|
- db-user:/db
|
||||||
|
- log-user:/var/log
|
||||||
networks:
|
networks:
|
||||||
- front
|
- front
|
||||||
- back
|
- back
|
||||||
@ -13,6 +14,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- TZ=Europe/Paris
|
- TZ=Europe/Paris
|
||||||
- API_TARGET=user
|
- API_TARGET=user
|
||||||
|
- LOG_FILE_PATH=/var/log/log.log
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
auth-api:
|
auth-api:
|
||||||
@ -22,12 +24,17 @@ services:
|
|||||||
context: ../../
|
context: ../../
|
||||||
volumes:
|
volumes:
|
||||||
- db-auth:/db
|
- db-auth:/db
|
||||||
|
- log-auth:/var/log
|
||||||
networks:
|
networks:
|
||||||
- front
|
- front
|
||||||
- back
|
- back
|
||||||
- prom-exporter
|
- prom-exporter
|
||||||
environment:
|
environment:
|
||||||
- TZ=Europe/Paris
|
- TZ=Europe/Paris
|
||||||
|
- GOOGLE_CALLBACK_URL=${GOOGLE_CALLBACK_URL}
|
||||||
|
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
|
||||||
|
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
|
||||||
- API_TARGET=auth
|
- API_TARGET=auth
|
||||||
|
- LOG_FILE_PATH=/var/log/log.log
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
@ -6,3 +6,4 @@ include:
|
|||||||
- ./monitoring/compose.yml
|
- ./monitoring/compose.yml
|
||||||
- ./api-base/compose.yml
|
- ./api-base/compose.yml
|
||||||
- ./front/compose.yml
|
- ./front/compose.yml
|
||||||
|
- ./ELK/compose.yml
|
||||||
|
@ -25,5 +25,11 @@ COPY --chmod=755 docker/front/entry/ssl-cert.sh /docker-entrypoint.d/ssl-cert.s
|
|||||||
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
USER root
|
||||||
|
RUN mkdir -p /var/log/front
|
||||||
|
RUN touch /var/log/front/err.log /var/log/front/log.log
|
||||||
|
RUN chmod -R 777 /var/log/front
|
||||||
|
USER nginx
|
||||||
|
|
||||||
EXPOSE 80 443
|
EXPOSE 80 443
|
||||||
STOPSIGNAL SIGINT
|
STOPSIGNAL SIGINT
|
||||||
|
@ -6,8 +6,9 @@ services:
|
|||||||
context: ../../
|
context: ../../
|
||||||
ports:
|
ports:
|
||||||
- ${OUT_PORT}:443
|
- ${OUT_PORT}:443
|
||||||
|
volumes:
|
||||||
|
- log-nginx:/var/log/front
|
||||||
environment:
|
environment:
|
||||||
- SERVER_NAME=localhost
|
|
||||||
- TZ=Europe/Paris
|
- TZ=Europe/Paris
|
||||||
depends_on:
|
depends_on:
|
||||||
user-api:
|
user-api:
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
server {
|
server {
|
||||||
|
error_log /var/log/front/err.log warn;
|
||||||
|
access_log /var/log/front/log.log;
|
||||||
|
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
server_name example.com; # Replace with your domain or handle env vars externally
|
server_name example.com; # Replace with your domain or handle env vars externally
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ scrape_configs:
|
|||||||
static_configs:
|
static_configs:
|
||||||
- targets: ['node-exporter:9100']
|
- targets: ['node-exporter:9100']
|
||||||
|
|
||||||
- job_name: 'nodejs'
|
# - job_name: 'nodejs'
|
||||||
static_configs:
|
# static_configs:
|
||||||
- targets: ['transcendence-api-auth:3000']
|
# - targets: ['transcendence-api-auth:3000']
|
||||||
- targets: ['transcendence-api-user:3000']
|
# - targets: ['transcendence-api-user:3000']
|
||||||
|
@ -7,3 +7,7 @@ networks:
|
|||||||
name: transcendence-prom
|
name: transcendence-prom
|
||||||
prom-exporter:
|
prom-exporter:
|
||||||
name: transcendence-prom-exporter
|
name: transcendence-prom-exporter
|
||||||
|
elk:
|
||||||
|
name: transcendence-elk
|
||||||
|
logstash:
|
||||||
|
name: transcendence-logstash
|
||||||
|
@ -5,3 +5,9 @@ volumes:
|
|||||||
name: transcendence-api-auth-db
|
name: transcendence-api-auth-db
|
||||||
db-user:
|
db-user:
|
||||||
name: transcendence-api-user-db
|
name: transcendence-api-user-db
|
||||||
|
log-auth:
|
||||||
|
name: transcendence-api-auth-log
|
||||||
|
log-user:
|
||||||
|
name: transcendence-api-user-log
|
||||||
|
log-nginx:
|
||||||
|
name: transcendence-front-log
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
fi
|
fi
|
||||||
if [ ! -d lib/ ]; then
|
if [ ! -d lib/ ]; then
|
||||||
echo Installing foundry env
|
echo Installing foundry env
|
||||||
forge i
|
forge i
|
||||||
fi
|
fi
|
||||||
export PATH+=:$(pwd)/node_modules/.bin
|
export PATH+=:$(pwd)/node_modules/.bin
|
||||||
echo entering ft_trans env
|
echo entering ft_trans env
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"ethers": "^6.15.0",
|
"ethers": "^6.15.0",
|
||||||
"fastify": "^5.4.0",
|
"fastify": "^5.4.0",
|
||||||
"fastify-cli": "^7.4.0",
|
"fastify-cli": "^7.4.0",
|
||||||
"google-auth-library": "^10.1.0",
|
"pino": "^9.7.0",
|
||||||
"prom-client": "^15.1.3",
|
"prom-client": "^15.1.3",
|
||||||
"solhint": "^6.0.0"
|
"solhint": "^6.0.0"
|
||||||
},
|
},
|
||||||
|
3277
pnpm-lock.yaml
generated
3277
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,5 @@
|
|||||||
import fastifyJWT from '@fastify/jwt';
|
import fastifyJWT from '@fastify/jwt';
|
||||||
import fastifyCookie from '@fastify/cookie';
|
import fastifyCookie from '@fastify/cookie';
|
||||||
import client from 'prom-client';
|
|
||||||
|
|
||||||
import { register } from './register.js';
|
import { register } from './register.js';
|
||||||
import { login } from './login.js';
|
import { login } from './login.js';
|
||||||
@ -14,7 +13,6 @@ import { totpVerify } from './totpVerify.js';
|
|||||||
|
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
export const appName = process.env.APP_NAME || 'knl_meowscendence';
|
export const appName = process.env.APP_NAME || 'knl_meowscendence';
|
||||||
const collectDefaultMetrics = client.collectDefaultMetrics
|
|
||||||
|
|
||||||
authDB.prepareDB();
|
authDB.prepareDB();
|
||||||
|
|
||||||
@ -24,29 +22,6 @@ authDB.prepareDB();
|
|||||||
*/
|
*/
|
||||||
export default async function(fastify, options) {
|
export default async function(fastify, options) {
|
||||||
|
|
||||||
collectDefaultMetrics({ labels: { service: "auth-api" } })
|
|
||||||
client.register.setDefaultLabels({ service: "auth-api" })
|
|
||||||
|
|
||||||
const httpRequestCounter = new client.Counter({
|
|
||||||
name: 'http_requests_total',
|
|
||||||
help: 'Total number of HTTP requests',
|
|
||||||
labelNames: ['method', 'route', 'status_code'],
|
|
||||||
})
|
|
||||||
|
|
||||||
fastify.addHook('onResponse', (req, res, done) => {
|
|
||||||
httpRequestCounter.inc({
|
|
||||||
method: req.method,
|
|
||||||
route: req.routerPath || req.url,
|
|
||||||
status_code: res.statusCode,
|
|
||||||
})
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
fastify.get('/metrics', async (req, reply) => {
|
|
||||||
reply
|
|
||||||
.header('Content-Type', client.register.contentType)
|
|
||||||
.send(await client.register.metrics())
|
|
||||||
})
|
|
||||||
|
|
||||||
fastify.register(fastifyJWT, {
|
fastify.register(fastifyJWT, {
|
||||||
secret: process.env.JWT_SECRET || '123456789101112131415161718192021',
|
secret: process.env.JWT_SECRET || '123456789101112131415161718192021',
|
||||||
cookie: {
|
cookie: {
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import fastifyJWT from '@fastify/jwt';
|
import fastifyJWT from '@fastify/jwt';
|
||||||
import fastifyCookie from '@fastify/cookie';
|
import fastifyCookie from '@fastify/cookie';
|
||||||
import Database from 'better-sqlite3';
|
import Database from 'better-sqlite3';
|
||||||
import client from 'prom-client';
|
|
||||||
|
|
||||||
var env = process.env.NODE_ENV || 'development';
|
var env = process.env.NODE_ENV || 'development';
|
||||||
const collectDefaultMetrics = client.collectDefaultMetrics
|
|
||||||
|
|
||||||
let database;
|
let database;
|
||||||
|
|
||||||
@ -58,31 +56,6 @@ const deleteFriends = database.prepare('DELETE FROM friends WHERE username = ?;'
|
|||||||
* @param {import('fastify').FastifyPluginOptions} options
|
* @param {import('fastify').FastifyPluginOptions} options
|
||||||
*/
|
*/
|
||||||
export default async function(fastify, options) {
|
export default async function(fastify, options) {
|
||||||
|
|
||||||
collectDefaultMetrics({ labels: { service: "auth-api" } })
|
|
||||||
client.register.setDefaultLabels({ service: "auth-api" })
|
|
||||||
|
|
||||||
const httpRequestCounter = new client.Counter({
|
|
||||||
name: 'http_requests_total',
|
|
||||||
help: 'Total number of HTTP requests',
|
|
||||||
labelNames: ['method', 'route', 'status_code'],
|
|
||||||
})
|
|
||||||
|
|
||||||
fastify.addHook('onResponse', (req, res, done) => {
|
|
||||||
httpRequestCounter.inc({
|
|
||||||
method: req.method,
|
|
||||||
route: req.routerPath || req.url,
|
|
||||||
status_code: res.statusCode,
|
|
||||||
})
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
fastify.get('/metrics', async (req, reply) => {
|
|
||||||
reply
|
|
||||||
.header('Content-Type', client.register.contentType)
|
|
||||||
.send(await client.register.metrics())
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
fastify.register(fastifyJWT, {
|
fastify.register(fastifyJWT, {
|
||||||
secret: process.env.JWT_SECRET || '123456789101112131415161718192021',
|
secret: process.env.JWT_SECRET || '123456789101112131415161718192021',
|
||||||
cookie: {
|
cookie: {
|
||||||
|
108
src/start.js
108
src/start.js
@ -2,65 +2,81 @@ import Fastify from 'fastify';
|
|||||||
import authApi from './api/auth/default.js';
|
import authApi from './api/auth/default.js';
|
||||||
import userApi from './api/user/default.js';
|
import userApi from './api/user/default.js';
|
||||||
import scoreApi from './api/scoreStore/default.js';
|
import scoreApi from './api/scoreStore/default.js';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
const loggerOption = {
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
transport: {
|
const logFilePath = process.env.LOG_FILE_PATH || './logs/api.log';
|
||||||
target: 'pino-pretty',
|
|
||||||
options: {
|
const loggerOption = () => {
|
||||||
colorize: true,
|
if (!isProduction) {
|
||||||
translateTime: 'HH:MM:ss',
|
return {
|
||||||
ignore: 'pid,hostname'
|
transport: {
|
||||||
}
|
target: 'pino-pretty',
|
||||||
}
|
options: {
|
||||||
|
colorize: true,
|
||||||
|
translateTime: 'HH:MM:ss',
|
||||||
|
ignore: 'pid,hostname',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Make sure the directory exists
|
||||||
|
const logDir = path.dirname(logFilePath);
|
||||||
|
fs.mkdirSync(logDir, { recursive: true });
|
||||||
|
|
||||||
|
const logStream = fs.createWriteStream(logFilePath, { flags: 'a' }); // append mode
|
||||||
|
return {
|
||||||
|
level: 'info',
|
||||||
|
stream: logStream,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function sigHandle(signal) {
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.on('SIGINT', sigHandle);
|
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
const target = process.env.API_TARGET || 'all';
|
const target = process.env.API_TARGET || 'all';
|
||||||
|
|
||||||
|
const servers = [];
|
||||||
|
|
||||||
if (target === 'auth' || target === 'all') {
|
if (target === 'auth' || target === 'all') {
|
||||||
const auth = Fastify({ logger: loggerOption });
|
const auth = Fastify({ logger: loggerOption('auth') });
|
||||||
auth.register(authApi);
|
auth.register(authApi);
|
||||||
if (target !== 'all') {
|
const port = target === 'all' ? 3001 : 3000;
|
||||||
await auth.listen({ port: 3000, host: '0.0.0.0' });
|
const host = target === 'all' ? '127.0.0.1' : '0.0.0.0';
|
||||||
console.log('Auth API listening on http://0.0.0.0:3000');
|
await auth.listen({ port, host });
|
||||||
}
|
console.log(`Auth API listening on http://${host}:${port}`);
|
||||||
else {
|
servers.push(auth);
|
||||||
await auth.listen({ port: 3001, host: '127.0.0.1'});
|
|
||||||
console.log('Auth API listening on http://localhost:3001');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target === 'user' || target === 'all') {
|
if (target === 'user' || target === 'all') {
|
||||||
const user = Fastify({ logger: loggerOption });
|
const user = Fastify({ logger: loggerOption('user') });
|
||||||
user.register(userApi);
|
user.register(userApi);
|
||||||
if (target !== 'all') {
|
const port = target === 'all' ? 3002 : 3000;
|
||||||
await user.listen({ port: 3000, host: '0.0.0.0' });
|
const host = target === 'all' ? '127.0.0.1' : '0.0.0.0';
|
||||||
console.log('User API listening on http://0.0.0.0:3000');
|
await user.listen({ port, host });
|
||||||
}
|
console.log(`User API listening on http://${host}:${port}`);
|
||||||
else {
|
servers.push(user);
|
||||||
await user.listen({ port: 3002, host: '127.0.0.1'});
|
}
|
||||||
console.log('User API listening on http://localhost:3002');
|
|
||||||
}
|
if (target === 'scoreScore' || target === 'all') {
|
||||||
|
const score = Fastify({ logger: loggerOption('scoreStore') });
|
||||||
|
score.register(scoreApi);
|
||||||
|
const port = target === 'all' ? 3002 : 3000;
|
||||||
|
const host = target === 'all' ? '127.0.0.1' : '0.0.0.0';
|
||||||
|
await score.listen({ port, host });
|
||||||
|
console.log(`ScoreStore API listening on http://${host}:${port}`);
|
||||||
|
servers.push(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target === 'scoreStore' || target === 'all') {
|
// Graceful shutdown on SIGINT
|
||||||
const scoreStore = Fastify({ logger: loggerOption });
|
process.on('SIGINT', async () => {
|
||||||
scoreStore.register(scoreApi);
|
console.log('SIGINT received, closing servers...');
|
||||||
if (target !== 'all') {
|
await Promise.all(servers.map((srv) => srv.close()));
|
||||||
await scoreStore.listen({ port: 3000, host: '0.0.0.0' });
|
process.exit(0);
|
||||||
console.log('scoreStore API listening on http://0.0.0.0:3000');
|
});
|
||||||
}
|
|
||||||
else {
|
|
||||||
await scoreStore.listen({ port: 3002, host: '127.0.0.1'});
|
|
||||||
console.log('scoreStore API listening on http://localhost:3002');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start().catch(console.error);
|
start().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
Reference in New Issue
Block a user