Commit aa4655ee authored by Konrad Mohrfeldt's avatar Konrad Mohrfeldt

add environment configuration support

This adds limited support for environment configuration. Available
options are outlined in the `Custom Enviroments` section in the readme.

For now the only configurable setting is the `apiOrigin` making it
possible to switch the origin of the thekno API without creating a
separate build.

Environment configuration is provided by the `/thekno-env.json`
endpoint.
parent ff5ea6a3
Pipeline #1659 failed with stages
in 59 seconds
......@@ -10,6 +10,8 @@ RUN npm run build
# stage-2: copy static files to nginx image
FROM nginx:alpine
EXPOSE 5000
ARG env_file=system-files/env-prod.json
COPY system-files/nginx-defaultsite.conf /etc/nginx/conf.d/thekno.conf
COPY system-files/nginx-spa.conf /etc/nginx/snippets/thekno-spa.include
COPY --from=build /usr/src/app/build/dist /usr/share/thekno/html
COPY $env_file /usr/share/thekno/html/thekno-env.json
......@@ -15,20 +15,40 @@ The project uses a number of external dependencies, that you can install with th
PROXY_TARGET="https://thek.lohro.de/" npm run serve
```
You may also use the included docker script `scripts/docker.sh`. It will build and start *thekno* in an environment similar to those in production. Providing a [custom environment](#custom-environment) is possible with the `--build-arg` option like this:
```sh
scripts/docker.sh --build-arg env_file=path/to/my/environment-file.json
```
## Contributions
Contributions are always welcome. Before you push your commits or create *merge requests* make sure that `npm run lint` and `npm run test` do not report any errors (that did not exist before 😅).
## Builds & Deployment
VueJS provides a build target out of the box. You can create a build with `npm run build` and deploy the contents of the `build/dist` directory afterwards. There is also a `Dockerfile` that can be used to create docker images (in fact this `Dockerfile` is used to automatically deploy *thekno* to our [staging server](https://lohro-lohrothek-thekno-staging.lohrothek.git-k8s.hack-hro.de/)).
VueJS provides a build target out of the box. You can create a build with `npm run build` and deploy the contents of the `build/dist` directory afterwards. There is also a `Dockerfile` that can be used to create docker images (in fact it’s used to automatically deploy *thekno* to our [staging server](https://lohro-lohrothek-thekno-staging.lohrothek.git-k8s.hack-hro.de/)).
There will also be a deb package for Debian at a later point.
See [Custom Environments](#custom-environments) for a way to alter the default behaviour of *thekno*.
## Custom Environments
*thekno* supports some environment configuration. You may put the following options in a JSON file and serve it under the `/thekno-env.json` endpoint.
apiOrigin:
Origin (`protocol://host:port`, e.g. `http://localhost:8000` or `https://thek.lohro.de`) of the [*thekno* API](https://git.hack-hro.de/lohro/lohrothek/lohrothek-api).
There will also be a deb package for Debian at a later point.
## System Requirements
This projects requires fairly recent versions of *NodeJS* (v8+) and *npm* (v5.8+). Both are bundled with the default distribution available on [nodejs.org](https://nodejs.org/en/download/).
### Debian Stretch
If you are using Debian Stretch you’ll notice that the distributed `nodejs` package is fairly old and that npm is missing entirely.
......@@ -45,10 +65,12 @@ After that you will be able to install `nodejs` and `npm` with the following com
apt update && apt install -t stretch-backports nodejs npm
```
### Debian Buster
Debian Buster ships with the required versions so that you can just install the `nodejs` and `npm` packages.
### Other Distributions & Windows
For all other distributions that do not contain the required *NodeJS* and *npm* packages visit the [download section](https://nodejs.org/en/download/) on the NodeJS page.
......
......@@ -7,7 +7,7 @@
"build": "vue-cli-service build --modern",
"test": "npm run lint",
"lint": "vue-cli-service lint",
"docker": "docker build . -t thekno && docker run -d -p 5000:5000 thekno"
"docker": "scripts/docker.sh"
},
"dependencies": {
"axios": "^0.18.0",
......
#!/bin/sh
set -eu
docker build . -t thekno "$@" && docker run -d -p 5000:5000 thekno
export class TheknoError extends Error {
toString () {
let baseMessage = `${this.message}\nCode: ${this.code}`
if (this.instructions) {
baseMessage += '\n\n' + this.instructions
}
return baseMessage
}
}
export class TheknoNoApiError extends TheknoError {
constructor (message = 'Unable to determine API endpoint') {
super(message)
this.code = 'THEKNO_NOAPI'
this.instructions =
'Thekno was unable to find the API endpoint used to fetch data. ' +
'Either you configure one by delivering a config through the `/thekno-env.json`-endpoint (see docs) ' +
'or enable API access through the `/api/v1/` endpoint on this origin.'
}
}
export function errorToHtml (e, title) {
return `
<div style="max-width: 600px; margin: 5rem auto; color: crimson; font-family: sans-serif">
<h1 style="margin-bottom: .5em">${title}</h1>
<pre style="white-space: pre-wrap">${String(e)}</pre>
</div>`
}
......@@ -3,9 +3,10 @@ import VueFeather from 'vue-feather'
import './plugins/vuetify'
import App from './App.vue'
import router from './router'
import store from './store'
import createStore from './store'
import i18n from './i18n'
import Player from './player'
import { TheknoNoApiError, errorToHtml } from './error'
Vue.config.productionTip = false
Vue.config.keyCodes = {
......@@ -18,9 +19,38 @@ Vue.config.keyCodes = {
Vue.use(Player)
Vue.use(VueFeather)
new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount('#app')
const { location, fetch } = window
function init (env) {
const store = createStore(env)
new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount('#app')
}
fetch('/thekno-env.json')
.then(res => res.json())
.catch(e => {
if (/^Unexpected token/.test(e.message)) {
// Looks like the response could not be parsed as JSON.
// Maybe the default route handler kicked in returning the index.html.
// Try the current origin path for the API and if that fails give up.
return fetch('/api/v1/')
.then(res => res.json())
.then(
() => ({ apiOrigin: location.origin }),
() => { throw new TheknoNoApiError() })
} else {
// We’re out of ideas what might have gone wrong.
// Rethrow and use general error handling.
throw e
}
})
.then(init, e => {
document.querySelector('#app').innerHTML =
errorToHtml(e, 'Could not initialize thekno app')
})
import Vapi from 'vuex-rest-api'
export default ({ axios }) => {
export default ({ axios, apiOrigin }) => {
const storeConfig = new Vapi({
baseURL: '/api/v1/broadcasts',
baseURL: `${apiOrigin}/api/v1/broadcasts`,
axios,
state: {
broadcasts: []
......
import Vapi from 'vuex-rest-api'
export default ({ axios }) => {
export default ({ axios, apiOrigin }) => {
const storeConfig = new Vapi({
baseURL: '/api/v1/recordings',
baseURL: `${apiOrigin}/api/v1/recordings`,
axios,
state: {
recordings: []
......
import Vapi from 'vuex-rest-api'
export default ({ axios }) => {
export default ({ axios, apiOrigin }) => {
const storeConfig = new Vapi({
baseURL: '/api/v1/series',
baseURL: `${apiOrigin}/api/v1/series`,
axios,
state: {
series: []
......
......@@ -3,18 +3,22 @@ import Vuex from 'vuex'
import axios from './axios'
import createApiStore from './api'
import createViewStore from './view'
Vue.use(Vuex)
const store = new Vuex.Store({
strict: process.env.NODE_ENV !== 'production',
modules: {
api: createApiStore({ axios })
}
})
export default function createStore (env) {
const store = new Vuex.Store({
strict: process.env.NODE_ENV !== 'production',
modules: {
api: createApiStore({ axios, ...env }),
misc: createViewStore()
}
})
store.dispatch('api/getBroadcasts')
store.dispatch('api/getRecordings')
store.dispatch('api/getSeries')
store.dispatch('api/getBroadcasts')
store.dispatch('api/getRecordings')
store.dispatch('api/getSeries')
export default store
return store
}
{
"apiOrigin": "https://thek.lohro.de"
}
# nginx default site for Docker image
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
......@@ -8,14 +7,7 @@ map $http_upgrade $connection_upgrade {
server {
listen 5000 default_server;
listen [::]:5000 default_server;
root /usr/share/thekno/html;
location /api/ {
proxy_pass https://thek.lohro.de;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
root /usr/share/thekno/html;
include /etc/nginx/snippets/thekno-spa.include;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment