mirror of
https://github.com/pawelmalak/flame.git
synced 2024-12-19 08:02:16 +03:00
Docker build. Catch client routes on server. Initial config utility
This commit is contained in:
parent
d2e6ebae4f
commit
1636b705de
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
17
Dockerfile
Normal file
17
Dockerfile
Normal 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
42
README.md
Normal 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
7
api.js
@ -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
4
db.js
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
11
package.json
11
package.json
@ -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",
|
||||||
|
12
server.js
12
server.js
@ -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()
|
||||||
associateModels();
|
.then(() => {
|
||||||
|
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
36
utils/initConfig.js
Normal 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;
|
@ -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();
|
||||||
@ -10,4 +11,9 @@ const weatherJob = schedule.scheduleJob('updateWeather', '0 */15 * * * *', async
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
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')
|
||||||
})
|
})
|
Loading…
Reference in New Issue
Block a user