Docker build. Catch client routes on server. Initial config utility

This commit is contained in:
unknown 2021-06-07 13:40:51 +02:00
parent d2e6ebae4f
commit 1636b705de
10 changed files with 125 additions and 13 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
node_modules

17
Dockerfile Normal file
View File

@ -0,0 +1,17 @@
FROM node:14-alpine
WORKDIR /app
COPY package*.json .
RUN npm install --only=production
COPY . .
RUN mkdir -p ./public ./data
RUN mv ./client/build/* ./public
RUN rm -rf ./client
EXPOSE 5005
CMD ["node", "server.js"]

42
README.md Normal file
View File

@ -0,0 +1,42 @@
# Flame
## Description
Flame is self-hosted startpage for your server. It's inspired (heavily) by [SUI](https://github.com/jeroenpardon/sui)
## Technology
- Backend
- Node.js + Express
- Sequelize ORM + SQLite
- Frontend
- React
- Redux
- TypeScript
- Deployment
- Docker
## Development
```sh
git clone https://github.com/pawelmalak/flame
cd flame
# run only once
<TODO>
# start backend and frontend development servers
npm run dev
```
## Deployment with Docker
```sh
# build image
docker build -t flame .
# run container
docker run \
-p 5005:5005 \
-v <host_dir>:/app/data \
flame
```
## Functionality
todo

7
api.js
View File

@ -1,10 +1,13 @@
const path = require('path');
const express = require('express'); const express = require('express');
const errorHandler = require('./middleware/errorHandler'); const errorHandler = require('./middleware/errorHandler');
const api = express(); const api = express();
api.get('/', (req, res) => { // Static files
res.send('Server is working'); api.use(express.static(path.join(__dirname, 'public')));
api.get(/^\/(?!api)/, (req, res) => {
res.sendFile(path.join(__dirname, 'public/index.html'));
}) })
// Body parser // Body parser

4
db.js
View File

@ -9,13 +9,13 @@ const sequelize = new Sequelize({
const connectDB = async () => { const connectDB = async () => {
try { try {
await sequelize.authenticate({ logging: false }); await sequelize.authenticate({ logging: false });
console.log('Connected to database'.cyan.underline); console.log('Connected to database');
await sequelize.sync({ await sequelize.sync({
// alter: true, // alter: true,
logging: false logging: false
}); });
console.log('All models were synced'.cyan.underline); console.log('All models were synced');
} catch (error) { } catch (error) {
console.error('Unable to connect to the database:', error); console.error('Unable to connect to the database:', error);
} }

View File

@ -11,7 +11,7 @@ const errorHandler = (err, req, res, next) => {
// } // }
console.log(error); console.log(error);
console.log(`${err}`.bgRed); console.log(`${err}`);
res.status(err.statusCode || 500).json({ res.status(err.statusCode || 500).json({
success: false, success: false,

View File

@ -5,10 +5,13 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "node server.js", "start": "node server.js",
"server": "nodemon server.js", "init-server": "echo Instaling server dependencies && npm install",
"client": "npm start --prefix client", "init-client": "cd client && echo Instaling client dependencies && npm install",
"dev": "concurrently \"npm run server\" \"npm run client\"", "dev-init": "npm run init-server && npm run init-client",
"dev-lines": "git ls-files | grep -v '.json' | xargs wc -l" "dev-server": "nodemon server.js",
"dev-client": "npm start --prefix client",
"dev": "concurrently \"npm run dev-server\" \"npm run dev-client\"",
"build": "docker build -t flame ."
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",

View File

@ -1,3 +1,4 @@
require('dotenv').config();
const http = require('http'); const http = require('http');
const { connectDB } = require('./db'); const { connectDB } = require('./db');
const api = require('./api'); const api = require('./api');
@ -5,12 +6,15 @@ const jobs = require('./utils/jobs');
const Socket = require('./Socket'); const Socket = require('./Socket');
const Sockets = require('./Sockets'); const Sockets = require('./Sockets');
const associateModels = require('./models/associateModels'); const associateModels = require('./models/associateModels');
const initConfig = require('./utils/initConfig');
require('dotenv').config();
const PORT = process.env.PORT || 5005; const PORT = process.env.PORT || 5005;
connectDB(); connectDB()
.then(() => {
associateModels(); associateModels();
initConfig();
});
// Create server for Express API and WebSockets // Create server for Express API and WebSockets
const server = http.createServer(); const server = http.createServer();
@ -21,5 +25,5 @@ const weatherSocket = new Socket(server);
Sockets.registerSocket('weather', weatherSocket); Sockets.registerSocket('weather', weatherSocket);
server.listen(PORT, () => { server.listen(PORT, () => {
console.log(`Server is running on port ${PORT} in ${process.env.NODE_ENV} mode`.yellow.bold); console.log(`Server is running on port ${PORT} in ${process.env.NODE_ENV} mode`);
}) })

36
utils/initConfig.js Normal file
View File

@ -0,0 +1,36 @@
const { Op } = require('sequelize');
const Config = require('../models/Config');
const initConfig = async () => {
// Config keys
const keys = ['WEATHER_API_KEY', 'lat', 'long', 'isCelsius'];
const values = ['', 0, 0, true];
// Get config values
const configPairs = await Config.findAll({
where: {
key: {
[Op.or]: keys
}
}
})
// Get key from each pair
const configKeys = configPairs.map((pair) => pair.key);
// Create missing pairs
keys.forEach(async (key, idx) => {
if (!configKeys.includes(key)) {
await Config.create({
key,
value: values[idx],
valueType: typeof values[idx]
})
}
})
console.log('Initial config created');
return;
}
module.exports = initConfig;

View File

@ -2,6 +2,7 @@ const schedule = require('node-schedule');
const getExternalWeather = require('./getExternalWeather'); const getExternalWeather = require('./getExternalWeather');
const Sockets = require('../Sockets'); const Sockets = require('../Sockets');
// Update weather data every 15 minutes
const weatherJob = schedule.scheduleJob('updateWeather', '0 */15 * * * *', async () => { const weatherJob = schedule.scheduleJob('updateWeather', '0 */15 * * * *', async () => {
try { try {
const weatherData = await getExternalWeather(); const weatherData = await getExternalWeather();
@ -11,3 +12,8 @@ const weatherJob = schedule.scheduleJob('updateWeather', '0 */15 * * * *', async
console.log(err.message); console.log(err.message);
} }
}) })
// Clear old weather data every 4 hours
const weatherCleanerJob = schedule.scheduleJob('clearWeather', '0 0 */4 * * *', async () => {
console.log('clean')
})