mirror of
https://github.com/cpvalente/ontime.git
synced 2026-07-26 10:38:55 +00:00
Docker (#146)
* docker: initial config * docker: add entrypoint for headless run * docker: resolve path from env variable * docker: initial config * docker: rename preloaded data directories * docker: update README * docker: prevent issue with port mappings * docker: update README.md * docker: add docker-compose * docker: cleanup logs * docker: add CI * docker: cleanup unused * docker: use static port in development * refactor: isolate tasks * docker: add demo db * fix: download db resolves according to OS * docker: config build * fix: ensure db path exists * fix: add object type to block * docker: config build * docker: config build * docker: env is production * docker: preload db * fix: remove test dir * docker: graceful shutdown node app * docker: env is production * docker: add docker-compose * docker: remove unused mappings * docker: version bump
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# Ignore config files
|
||||
.prettier*
|
||||
|
||||
# Ignore install stuff
|
||||
**/yarn.lock
|
||||
**/yarn-error.log
|
||||
|
||||
# Ignore test files
|
||||
**/__tests__/**
|
||||
**/**.test.js
|
||||
|
||||
# Ignore git and cache folders
|
||||
.git
|
||||
.cache
|
||||
@@ -1,103 +0,0 @@
|
||||
# This is a basic workflow to help you get started with Actions
|
||||
|
||||
name: CI
|
||||
|
||||
# Controls when the action will run.
|
||||
on:
|
||||
push:
|
||||
# Pattern matched against refs/tags
|
||||
tags:
|
||||
# Push events to every tag not containing /
|
||||
- '*'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
# build a file for windows
|
||||
buildwin:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
CI: ''
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '14.x'
|
||||
|
||||
# install and build react
|
||||
- name: Install React dependencies
|
||||
run: yarn install
|
||||
working-directory: ./client
|
||||
- name: Build React App
|
||||
run: yarn build
|
||||
working-directory: ./client
|
||||
|
||||
# install node dependencies
|
||||
- name: Install nodejs dependencies
|
||||
run: yarn install
|
||||
working-directory: ./server/src
|
||||
|
||||
# install and build electron
|
||||
- name: Install Electron dependencies
|
||||
run: yarn install
|
||||
working-directory: ./server
|
||||
- name: Build Electron App
|
||||
run: yarn dist-win
|
||||
working-directory: ./server
|
||||
|
||||
# release
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: ./server/dist/ontime-win64.exe
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# build a file for mac
|
||||
# buildmac:
|
||||
# The type of runner that the job will run on
|
||||
# runs-on: macOS-latest
|
||||
# env:
|
||||
# CI: ''
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
# steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
# - uses: actions/checkout@v2
|
||||
|
||||
# - name: Use Node.js
|
||||
# uses: actions/setup-node@v1
|
||||
# with:
|
||||
# node-version: '14.x'
|
||||
|
||||
# install and build react
|
||||
# - name: Install React dependencies
|
||||
# run: yarn install
|
||||
# working-directory: ./client
|
||||
# - name: Build React App
|
||||
# run: yarn build
|
||||
# working-directory: ./client
|
||||
|
||||
# install and build electron
|
||||
# - name: Install Electron + nodejs dependencies
|
||||
# run: yarn install
|
||||
# working-directory: ./server
|
||||
# - name: Build Electron App
|
||||
# run: yarn dist-win
|
||||
# working-directory: ./server
|
||||
|
||||
# release
|
||||
# - name: Release
|
||||
# uses: softprops/action-gh-release@v1
|
||||
# with:
|
||||
# files: ./server/dist/ontime-macOS.dmg
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
|
||||
# React
|
||||
- name: React - Install dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
working-directory: ./client
|
||||
|
||||
- name: React - Build project
|
||||
@@ -31,13 +31,13 @@ jobs:
|
||||
|
||||
# Node server
|
||||
- name: Server - Install dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile --production
|
||||
working-directory: ./server/src
|
||||
|
||||
# App
|
||||
- name: Electron - Install dependencies
|
||||
shell: bash
|
||||
run: yarn install && yarn setdb
|
||||
run: yarn install --frozen-lockfile && yarn setdb
|
||||
working-directory: ./server
|
||||
- name: Electron - Build app
|
||||
run: yarn dist-mac
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
|
||||
# React
|
||||
- name: React - Install dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
working-directory: ./client
|
||||
|
||||
- name: React - Build project
|
||||
@@ -74,13 +74,13 @@ jobs:
|
||||
|
||||
# Node server
|
||||
- name: Server - Install dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile --production
|
||||
working-directory: ./server/src
|
||||
|
||||
# App
|
||||
- name: Electron - Install dependencies
|
||||
shell: bash
|
||||
run: yarn install && yarn setdb
|
||||
run: yarn install --frozen-lockfile && yarn setdb
|
||||
working-directory: ./server
|
||||
- name: Electron - Build app
|
||||
run: yarn dist-win
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
|
||||
# React
|
||||
- name: React - Install dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
working-directory: ./client
|
||||
|
||||
- name: React - Build project
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
|
||||
# Node server
|
||||
- name: Server - Install dependencies
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile --production
|
||||
working-directory: ./server/src
|
||||
|
||||
# App
|
||||
@@ -136,3 +136,49 @@ jobs:
|
||||
files: ./server/dist/ontime-linux.AppImage
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
publish_docker:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI: ''
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '14.x'
|
||||
|
||||
# React
|
||||
- name: React - Install dependencies
|
||||
run: yarn install
|
||||
working-directory: ./client
|
||||
|
||||
- name: React - Build project
|
||||
run: yarn build
|
||||
working-directory: ./client
|
||||
|
||||
# Node server
|
||||
- name: Server - Install dependencies
|
||||
run: yarn install --frozen-lockfile --production
|
||||
working-directory: ./server/src
|
||||
|
||||
# Login to docker
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Build and push
|
||||
- name: Build and push
|
||||
working-directory: ./
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/ontime:${{ env.RELEASE_VERSION }}
|
||||
|
||||
+2
-1
@@ -28,9 +28,10 @@ yarn-error.log*
|
||||
# working stuff
|
||||
_SS/
|
||||
db backup.json
|
||||
server/src/data/db.json
|
||||
server/src/preloaded-db/db.json
|
||||
server/src/models/db.json
|
||||
TODO.md
|
||||
ontime-db/
|
||||
|
||||
# vscode stuff
|
||||
.vscode/*
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
FROM node:14-alpine
|
||||
|
||||
WORKDIR /app/server
|
||||
|
||||
# Prepare UI
|
||||
COPY /client/build ../client/build
|
||||
|
||||
# Prepare Backend
|
||||
COPY /server/src ./
|
||||
|
||||
# Export default ports Main - OSC IN
|
||||
EXPOSE 4001/tcp 8888/udp
|
||||
ENV NODE_ENV=production
|
||||
ENV ONTIME_DATA=/server/
|
||||
|
||||
CMD ["yarn", "start:headless"]
|
||||
|
||||
# Build an run commandsN
|
||||
# docker build -t getontime/ontime .
|
||||
# docker run -p 4001:4001 -p 10.0.0.12:8888:8888/udp --mount type=bind,source="$(pwd)/ontime-db",target=/server/preloaded-db getontime/ontime
|
||||
@@ -78,6 +78,8 @@ More documentation available [here](https://cpvalente.gitbook.io/ontime/)
|
||||
- [x] Logging view
|
||||
- [x] Edit anywhere: run ontime in your local network and use any machine to reach the editor page (
|
||||
same as app)
|
||||
- [x] Multi platform (available on Windows, MacOS and Linux)
|
||||
- [x] [Headless run](#headless-run) (run server only, configure from a browser locally)
|
||||
|
||||
## Unopinionated
|
||||
|
||||
@@ -115,6 +117,29 @@ See [this repository](https://github.com/cpvalente/ontime-viewer-template) with
|
||||
how to get you started and read the docs about
|
||||
the [Websocket API](https://app.gitbook.com/s/-Mc0giSOToAhq0ROd0CR/control-and-feedback/websocket-api)
|
||||
|
||||
### Headless run️
|
||||
You can self host and run ontime in a docker image, the run command should:
|
||||
- expose the necessary ports (listen in Dockerfile)
|
||||
- mount a local file to persist your data (in the example: ````$(pwd)/local-data````)
|
||||
- the image name __getontime/ontime__
|
||||
|
||||
The docker image is in [available Docker Hub at getontime/ontime](https://hub.docker.com/r/getontime/ontime)
|
||||
```bash
|
||||
docker pull getontime/ontime
|
||||
```
|
||||
|
||||
```bash
|
||||
# Port 4001 - ontime server port
|
||||
# Port 8888 - OSC input, bound to localhost IP Address
|
||||
docker run -p 4001:4001 -p 127.0.0.1:8888:8888/udp --mount type=bind,source="$(pwd)/ontime-db",target=/server/preloaded-db getontime/ontime
|
||||
```
|
||||
|
||||
or if running from the docker compose
|
||||
|
||||
```bash
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
### Continued development
|
||||
@@ -126,7 +151,6 @@ friendly order unless there is user demand to bump any of them.
|
||||
- [ ] Improvement with event component design
|
||||
- [ ] New playback mode
|
||||
for [cumulative time keeping](https://github.com/cpvalente/ontime/issues/100)
|
||||
- [ ] Headless version (run server only anywhere, configure from a browser locally)
|
||||
- [ ] Companion module
|
||||
- [ ] Lower Third Manager
|
||||
- [ ] Note only event
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const NODE_PORT = 4001;
|
||||
export const STATIC_PORT = 4001;
|
||||
export const EVENT_TABLE = 'event';
|
||||
export const ALIASES = 'aliases';
|
||||
export const USERFIELDS = 'userFields';
|
||||
@@ -8,15 +8,18 @@ export const OSC_SETTINGS = 'oscSettings';
|
||||
export const APP_SETTINGS = 'appSettings';
|
||||
|
||||
/**
|
||||
* @description finds server path given the current location
|
||||
* @description finds server path given the current location, it
|
||||
* @return {*}
|
||||
*/
|
||||
const calculateServer = () => {
|
||||
return window.location.origin.replace(window.location.port, `${NODE_PORT}/`);
|
||||
if (process.env?.NODE_ENV === 'development') {
|
||||
return `http://localhost:${STATIC_PORT}`;
|
||||
}
|
||||
return window.location.origin;
|
||||
};
|
||||
|
||||
export const serverURL = calculateServer();
|
||||
export const eventURL = serverURL + EVENT_TABLE;
|
||||
export const eventsURL = serverURL + EVENTS_TABLE;
|
||||
export const playbackURL = `${serverURL}playback`;
|
||||
export const ontimeURL = `${serverURL}ontime`;
|
||||
export const eventURL = `${serverURL}/${EVENT_TABLE}`;
|
||||
export const eventsURL = `${serverURL}/${EVENTS_TABLE}`;
|
||||
export const playbackURL = `${serverURL}/playback`;
|
||||
export const ontimeURL = `${serverURL}/ontime`;
|
||||
|
||||
@@ -222,7 +222,9 @@ export const downloadEvents = async () => {
|
||||
filename = headerLine.substring(startFileNameIndex, endFileNameIndex);
|
||||
}
|
||||
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const url = window.URL.createObjectURL(
|
||||
new Blob([response.data], { type: 'application/json' })
|
||||
);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', filename);
|
||||
|
||||
@@ -154,15 +154,16 @@ const withSocket = (Component) => {
|
||||
// Filter events only to pass down
|
||||
useEffect(() => {
|
||||
if (eventsData == null) return;
|
||||
|
||||
// filter just events with title
|
||||
const pe = eventsData.filter(
|
||||
(d) => d.type === 'event' && d.title !== '' && d.isPublic === true
|
||||
);
|
||||
setPublicEvents(pe);
|
||||
if (Array.isArray(eventsData)) {
|
||||
const pe = eventsData.filter(
|
||||
(d) => d.type === 'event' && d.title !== '' && d.isPublic
|
||||
);
|
||||
setPublicEvents(pe);
|
||||
|
||||
// everything goes backstage
|
||||
setBackstageEvents(eventsData);
|
||||
// everything goes backstage
|
||||
setBackstageEvents(eventsData);
|
||||
}
|
||||
}, [eventsData]);
|
||||
|
||||
// Set general data
|
||||
@@ -178,13 +179,11 @@ const withSocket = (Component) => {
|
||||
/********************************************/
|
||||
// is there a now field?
|
||||
let showNow = true;
|
||||
if (!titles.titleNow && !titles.subtitleNow && !titles.presenterNow)
|
||||
showNow = false;
|
||||
if (!titles.titleNow && !titles.subtitleNow && !titles.presenterNow) showNow = false;
|
||||
|
||||
// is there a next field?
|
||||
let showNext = true;
|
||||
if (!titles.titleNext && !titles.subtitleNext && !titles.presenterNext)
|
||||
showNext = false;
|
||||
if (!titles.titleNext && !titles.subtitleNext && !titles.presenterNext) showNext = false;
|
||||
|
||||
const titleManager = { ...titles, showNow: showNow, showNext: showNext };
|
||||
|
||||
@@ -195,20 +194,12 @@ const withSocket = (Component) => {
|
||||
/********************************************/
|
||||
// is there a now field?
|
||||
let showPublicNow = true;
|
||||
if (
|
||||
!publicTitles.titleNow &&
|
||||
!publicTitles.subtitleNow &&
|
||||
!publicTitles.presenterNow
|
||||
)
|
||||
if (!publicTitles.titleNow && !publicTitles.subtitleNow && !publicTitles.presenterNow)
|
||||
showPublicNow = false;
|
||||
|
||||
// is there a next field?
|
||||
let showPublicNext = true;
|
||||
if (
|
||||
!publicTitles.titleNext &&
|
||||
!publicTitles.subtitleNext &&
|
||||
!publicTitles.presenterNext
|
||||
)
|
||||
if (!publicTitles.titleNext && !publicTitles.subtitleNext && !publicTitles.presenterNext)
|
||||
showPublicNext = false;
|
||||
|
||||
const publicTitleManager = {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
ontime:
|
||||
container_name: ontime
|
||||
image: getontime/ontime:test-alpine
|
||||
ports:
|
||||
- "4001:4001/tcp"
|
||||
- "127.0.0.1:8888:8888/udp"
|
||||
volumes:
|
||||
- "./ontime-db:/server/preloaded-db"
|
||||
restart: unless-stopped
|
||||
+6
-4
@@ -11,13 +11,16 @@ const {
|
||||
} = require('electron');
|
||||
const path = require('path');
|
||||
|
||||
const env = process.env.NODE_ENV || 'prod';
|
||||
if (process.env.NODE_ENV === undefined) {
|
||||
process.env.NODE_ENV = 'production';
|
||||
}
|
||||
const env = process.env.NODE_ENV;
|
||||
|
||||
let loaded = 'Nothing loaded';
|
||||
let isQuitting = false;
|
||||
|
||||
const nodePath =
|
||||
env !== 'prod'
|
||||
env !== 'production'
|
||||
? path.join('file://', __dirname, 'src/app.js')
|
||||
: path.join('file://', __dirname, '../', 'extraResources', 'src/app.js');
|
||||
|
||||
@@ -142,7 +145,7 @@ app.whenReady().then(() => {
|
||||
setTimeout(() => {
|
||||
// Load page served by node
|
||||
const reactApp =
|
||||
env === 'prod' ? 'http://localhost:4001/editor' : 'http://localhost:3000/editor';
|
||||
env === 'development' ? 'http://localhost:3000/editor' : 'http://localhost:4001/editor';
|
||||
|
||||
win.loadURL(reactApp).then(() => {
|
||||
win.webContents.setBackgroundThrottling(false);
|
||||
@@ -154,7 +157,6 @@ app.whenReady().then(() => {
|
||||
splash.destroy();
|
||||
|
||||
// tray stuff
|
||||
// TODO: get IP Address
|
||||
tray.setToolTip(loaded);
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ontime",
|
||||
"version": "1.1.1",
|
||||
"version": "1.2.0",
|
||||
"author": "Carlos Valente",
|
||||
"description": "Time keeping for live events",
|
||||
"repository": "https://github.com/cpvalente/ontime",
|
||||
@@ -27,7 +27,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"nodestart": "NODE_ENV=development node src/app.js",
|
||||
"setdb": "cp data/db.json src/data/db.json",
|
||||
"setdb": "cp demo-db/db.json src/preloaded-db/db.json",
|
||||
"clean": "rm -rf ../client/build/ && rm -rf ../client/node_modules && rm -rf src/node_modules && rm -rf ./node_modules && rm -rf ./dist",
|
||||
"prep": "yarn clean && yarn setdb",
|
||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||
|
||||
+9
-11
@@ -26,7 +26,7 @@ import { initiateOSC, shutdownOSCServer } from './controllers/OscController.js';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// get environment
|
||||
const env = process.env.NODE_ENV || 'prod';
|
||||
const env = process.env.NODE_ENV || 'production';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
@@ -56,11 +56,11 @@ app.use('/ontime', ontimeRouter);
|
||||
app.use('/playback', playbackRouter);
|
||||
|
||||
// serve react
|
||||
app.use(express.static(join(__dirname, env === 'prod' ? '../' : '../../', 'client/build')));
|
||||
app.use(express.static(join(__dirname, env === 'production' ? '../' : '../../', 'client/build')));
|
||||
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(
|
||||
resolve(__dirname, env === 'prod' ? '../' : '../../', 'client', 'build', 'index.html')
|
||||
resolve(__dirname, env === 'production' ? '../' : '../../', 'client', 'build', 'index.html'),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -107,14 +107,7 @@ export const startOSCServer = async (overrideConfig = null) => {
|
||||
const server = http.createServer(app);
|
||||
|
||||
export const startServer = async (overrideConfig = null) => {
|
||||
// Setup default port
|
||||
// const port = overrideConfig?.port || serverPort;
|
||||
|
||||
/* Note: Port is hardcoded
|
||||
* need to find a good solution for sharing
|
||||
* the dynamic info with the frontend
|
||||
*/
|
||||
const port = 4001;
|
||||
const port = 4001; // port hardcoded
|
||||
|
||||
// Start server
|
||||
const returnMessage = `Ontime is listening on port ${port}`;
|
||||
@@ -145,4 +138,9 @@ export const shutdown = async () => {
|
||||
global.timer.shutdown();
|
||||
};
|
||||
|
||||
// register shutdown signals
|
||||
process.once('SIGHUP', shutdown)
|
||||
process.once('SIGINT', shutdown)
|
||||
process.once('SIGTERM', shutdown)
|
||||
|
||||
export { server, app };
|
||||
|
||||
@@ -1403,7 +1403,7 @@ export class EventTimer extends Timer {
|
||||
this.messageStack.unshift(m);
|
||||
this.io.emit('logger', m);
|
||||
|
||||
if (process.env.NODE_ENV !== 'prod') {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.log(`[${m.level}] \t ${m.origin} \t ${m.text}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ export const config = {
|
||||
port: 4001,
|
||||
},
|
||||
database: {
|
||||
directory: 'preloaded-db',
|
||||
filename: 'db.json',
|
||||
tablename: 'events',
|
||||
},
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// get database
|
||||
import { data, db } from '../app.js';
|
||||
import { networkInterfaces } from 'os';
|
||||
import { fileHandler } from '../utils/parser.js';
|
||||
import { generateId } from '../utils/generate_id.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
import { resolveDbPath } from '../modules/loadDb.js';
|
||||
|
||||
// Create controller for GET request to '/ontime/poll'
|
||||
// Returns data for current state
|
||||
@@ -28,9 +22,9 @@ export const poll = async (req, res) => {
|
||||
// Returns -
|
||||
export const dbDownload = async (req, res) => {
|
||||
const fileTitle = data?.event?.title || 'ontime events';
|
||||
const dbFile = path.resolve(__dirname, '../', 'data/db.json');
|
||||
const dbInDisk = resolveDbPath();
|
||||
|
||||
res.download(dbFile, `${fileTitle}.json`, (err) => {
|
||||
res.download(dbInDisk, `${fileTitle}.json`, (err) => {
|
||||
if (err) {
|
||||
res.status(500).send({
|
||||
message: 'Could not download the file. ' + err,
|
||||
|
||||
@@ -8,16 +8,27 @@ import { dbModelv1 as dbModel } from '../models/dataModel.js';
|
||||
import { parseJson_v1 as parseJson } from '../utils/parser.js';
|
||||
|
||||
/**
|
||||
* @description ensures directories exist and picks available db path
|
||||
* @description Decides which path the database is in
|
||||
* @param ensure - whether it should create directory if it doesnt exist
|
||||
* @return {string}
|
||||
*/
|
||||
export const resolveDbPath = (ensure = true) => {
|
||||
const appPath = getAppDataPath();
|
||||
const dbDirectory = join(appPath, config.database.directory);
|
||||
if (ensure) {
|
||||
ensureDirectory(dbDirectory);
|
||||
}
|
||||
return join(dbDirectory, config.database.filename);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description ensures directories exist and populates database
|
||||
* @param runningDirectory
|
||||
* @return {string}
|
||||
*/
|
||||
const checkDirectories = (runningDirectory) => {
|
||||
const appPath = getAppDataPath();
|
||||
const dbDirectory = join(appPath, 'data');
|
||||
const dbInDisk = join(dbDirectory, config.database.filename);
|
||||
const startupDb = join(runningDirectory, 'data', config.database.filename);
|
||||
ensureDirectory(dbDirectory);
|
||||
const populateDb = (runningDirectory) => {
|
||||
const startupDb = join(runningDirectory, config.database.directory, config.database.filename);
|
||||
const dbInDisk = resolveDbPath();
|
||||
|
||||
// if dbInDisk doesnt exist we want to use startup db
|
||||
if (!existsSync(dbInDisk)) {
|
||||
@@ -53,7 +64,7 @@ const parseDb = async (fileToRead, adapterToUse) => {
|
||||
* @return {Promise<{data: (number|*), db: Low<unknown>}>}
|
||||
*/
|
||||
export default async function loadDb(runningDirectory) {
|
||||
const dbInDisk = checkDirectories(runningDirectory);
|
||||
const dbInDisk = populateDb(runningDirectory);
|
||||
|
||||
const adapter = new JSONFile(dbInDisk);
|
||||
const db = new Low(adapter);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"nodestart": "nodemon app.js",
|
||||
"start": "node app.js"
|
||||
"start": "node app.js",
|
||||
"start:headless": "NODE_ENV=production node run.js"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
(async () => {
|
||||
let loaded;
|
||||
try {
|
||||
const { startServer, startOSCServer } = await import('./app.js');
|
||||
// Start express server
|
||||
loaded = await startServer();
|
||||
|
||||
// Start OSC Server (API)
|
||||
await startOSCServer();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
console.log(loaded);
|
||||
})();
|
||||
@@ -15,20 +15,16 @@ export function ensureDirectory(directory) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Whether a file exists
|
||||
* @param directory
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function doesFileExist(directory) {
|
||||
return existsSync(directory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns public path depending on OS
|
||||
* @return {string|*}
|
||||
*/
|
||||
export function getAppDataPath() {
|
||||
// handle docker
|
||||
if (process.env.ONTIME_DATA) {
|
||||
return path.join(process.env.ONTIME_DATA);
|
||||
}
|
||||
|
||||
switch (process.platform) {
|
||||
case 'darwin': {
|
||||
return path.join(process.env.HOME, 'Library', 'Application Support', 'Ontime');
|
||||
|
||||
Reference in New Issue
Block a user