mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-18 01:50:50 +00:00
Add authentication (using Kilovolt v6)
This commit is contained in:
parent
27a7ede45e
commit
8e02ba6fb7
13 changed files with 505 additions and 12399 deletions
|
@ -6,7 +6,9 @@ module.exports = {
|
|||
'no-console': 0,
|
||||
'import/extensions': 0,
|
||||
'no-use-before-define': 'off',
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-use-before-define': ['error'],
|
||||
'@typescript-eslint/no-shadow': ['error'],
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
|
|
12612
frontend/package-lock.json
generated
12612
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,7 @@
|
|||
"@billjs/event-emitter": "^1.0.3",
|
||||
"@reach/router": "^1.3.4",
|
||||
"@reduxjs/toolkit": "^1.5.1",
|
||||
"@strimertul/kilovolt-client": "^5.0.1",
|
||||
"@strimertul/kilovolt-client": "^6.2.0",
|
||||
"@types/node": "^15.0.2",
|
||||
"@types/reach__router": "^1.3.7",
|
||||
"@types/react": "^17.0.5",
|
||||
|
@ -13,7 +13,6 @@
|
|||
"@vitejs/plugin-react": "^1.0.9",
|
||||
"bulma": "^0.9.2",
|
||||
"i18next": "^20.6.1",
|
||||
"parcel": "^2.0.1",
|
||||
"pretty-ms": "^7.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
@ -33,7 +32,6 @@
|
|||
"last 1 Chrome version"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@parcel/transformer-sass": "^2.0.0-beta.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.23.0",
|
||||
"@typescript-eslint/parser": "^4.23.0",
|
||||
"eslint": "^7.26.0",
|
||||
|
|
|
@ -54,7 +54,8 @@
|
|||
"server-bind": "HTTP server bind",
|
||||
"static-content": "Static content",
|
||||
"enable-static": "Enable static server",
|
||||
"static-root-path": "Static content root path"
|
||||
"static-root-path": "Static content root path",
|
||||
"kv-password": "Kilovolt password"
|
||||
},
|
||||
"backend": {
|
||||
"config": {
|
||||
|
@ -226,5 +227,11 @@
|
|||
"err-twitchbot-disabled": "Twitch bot must be enabled in order to use timers!",
|
||||
"enable": "Enable timers"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"message": "Strimertül's database is protected by a password, please write it below to access the control panel. If the database has no password (for example, it was recently changed from having one to none), leave the field empty.",
|
||||
"header": "Authorization needed",
|
||||
"placeholder": "Password",
|
||||
"button": "Authenticate"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,10 @@ import {
|
|||
PayloadAction,
|
||||
} from '@reduxjs/toolkit';
|
||||
import KilovoltWS from '@strimertul/kilovolt-client';
|
||||
import { kvError } from '@strimertul/kilovolt-client/lib/messages';
|
||||
import {
|
||||
APIState,
|
||||
ConnectionStatus,
|
||||
LoyaltyPointsEntry,
|
||||
LoyaltyRedeem,
|
||||
LoyaltyStorage,
|
||||
|
@ -63,8 +65,11 @@ function makeModule<T>(
|
|||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/no-mutable-exports, @typescript-eslint/ban-types
|
||||
export let setupClientReconnect: AsyncThunk<void, KilovoltWS, {}>;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
let setupClientReconnect: AsyncThunk<void, KilovoltWS, {}>;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
let kvErrorReceived: AsyncThunk<void, kvError, {}>;
|
||||
|
||||
// Storage
|
||||
const loyaltyPointsPrefix = 'loyalty/points/';
|
||||
|
@ -76,8 +81,11 @@ const loyaltyRemoveRedeemKey = 'loyalty/@remove-redeem';
|
|||
|
||||
export const createWSClient = createAsyncThunk(
|
||||
'api/createClient',
|
||||
async (address: string, { dispatch }) => {
|
||||
const client = new KilovoltWS(address);
|
||||
async (options: { address: string; password?: string }, { dispatch }) => {
|
||||
const client = new KilovoltWS(options.address, options.password);
|
||||
client.on('error', (err) => {
|
||||
dispatch(kvErrorReceived(err.data));
|
||||
});
|
||||
await client.wait();
|
||||
dispatch(setupClientReconnect(client));
|
||||
return client;
|
||||
|
@ -233,7 +241,8 @@ const moduleChangeReducers = Object.fromEntries(
|
|||
|
||||
const initialState: APIState = {
|
||||
client: null,
|
||||
connected: false,
|
||||
connectionStatus: ConnectionStatus.NotConnected,
|
||||
kvError: null,
|
||||
initialLoadComplete: false,
|
||||
loyalty: {
|
||||
users: null,
|
||||
|
@ -264,8 +273,14 @@ const apiReducer = createSlice({
|
|||
initialLoadCompleted(state) {
|
||||
state.initialLoadComplete = true;
|
||||
},
|
||||
connectionStatusChanged(state, { payload }: PayloadAction<boolean>) {
|
||||
state.connected = payload;
|
||||
connectionStatusChanged(
|
||||
state,
|
||||
{ payload }: PayloadAction<ConnectionStatus>,
|
||||
) {
|
||||
state.connectionStatus = payload;
|
||||
},
|
||||
kvErrorReceived(state, { payload }: PayloadAction<kvError>) {
|
||||
state.kvError = payload;
|
||||
},
|
||||
loyaltyUserPointsChanged(
|
||||
state,
|
||||
|
@ -279,7 +294,7 @@ const apiReducer = createSlice({
|
|||
extraReducers: (builder) => {
|
||||
builder.addCase(createWSClient.fulfilled, (state, { payload }) => {
|
||||
state.client = payload;
|
||||
state.connected = true;
|
||||
state.connectionStatus = ConnectionStatus.Connected;
|
||||
});
|
||||
builder.addCase(getUserPoints.fulfilled, (state, { payload }) => {
|
||||
state.loyalty.users = payload;
|
||||
|
@ -299,12 +314,38 @@ setupClientReconnect = createAsyncThunk(
|
|||
console.info('Attempting reconnection');
|
||||
client.reconnect();
|
||||
}, 5000);
|
||||
dispatch(apiReducer.actions.connectionStatusChanged(false));
|
||||
dispatch(
|
||||
apiReducer.actions.connectionStatusChanged(
|
||||
ConnectionStatus.NotConnected,
|
||||
),
|
||||
);
|
||||
});
|
||||
client.on('open', () => {
|
||||
dispatch(apiReducer.actions.connectionStatusChanged(true));
|
||||
dispatch(
|
||||
apiReducer.actions.connectionStatusChanged(ConnectionStatus.Connected),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
kvErrorReceived = createAsyncThunk(
|
||||
'api/kvErrorReceived',
|
||||
async (error: kvError, { dispatch }) => {
|
||||
switch (error.error) {
|
||||
case 'authentication required':
|
||||
case 'authentication failed':
|
||||
dispatch(
|
||||
apiReducer.actions.connectionStatusChanged(
|
||||
ConnectionStatus.AuthenticationNeeded,
|
||||
),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
// Unsupported error
|
||||
dispatch(apiReducer.actions.kvErrorReceived(error));
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export default apiReducer;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable camelcase */
|
||||
|
||||
import KilovoltWS from '@strimertul/kilovolt-client';
|
||||
import { kvError } from '@strimertul/kilovolt-client/lib/messages';
|
||||
|
||||
interface ModuleConfig {
|
||||
configured: boolean;
|
||||
|
@ -13,6 +14,7 @@ interface ModuleConfig {
|
|||
interface HTTPConfig {
|
||||
bind: string;
|
||||
enable_static_server: boolean;
|
||||
kv_password: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
|
@ -109,9 +111,16 @@ export interface LoyaltyRedeem {
|
|||
request_text: string;
|
||||
}
|
||||
|
||||
export enum ConnectionStatus {
|
||||
NotConnected,
|
||||
AuthenticationNeeded,
|
||||
Connected,
|
||||
}
|
||||
|
||||
export interface APIState {
|
||||
client: KilovoltWS;
|
||||
connected: boolean;
|
||||
connectionStatus: ConnectionStatus;
|
||||
kvError: kvError;
|
||||
initialLoadComplete: boolean;
|
||||
loyalty: {
|
||||
users: LoyaltyStorage;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Link, Redirect, Router, useLocation } from '@reach/router';
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -23,6 +23,8 @@ import TwitchBotModulesPage from './pages/twitch/Modules';
|
|||
import StulbeConfigPage from './pages/stulbe/Config';
|
||||
import StulbeWebhooksPage from './pages/stulbe/Webhook';
|
||||
import TwitchBotTimersPage from './pages/twitch/Timers';
|
||||
import { ConnectionStatus } from '../store/api/types';
|
||||
import Field from './components/Field';
|
||||
|
||||
interface RouteItem {
|
||||
name?: string;
|
||||
|
@ -59,27 +61,86 @@ const menu: RouteItem[] = [
|
|||
},
|
||||
];
|
||||
|
||||
function AuthModal(): React.ReactElement {
|
||||
const { t } = useTranslation();
|
||||
const [password, setPassword] = useState('');
|
||||
const inputRef = useRef<HTMLInputElement>();
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRef?.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
});
|
||||
|
||||
const submit = () => {
|
||||
localStorage.setItem('password', password);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="modal is-active">
|
||||
<div className="modal-background"></div>
|
||||
<div className="modal-card">
|
||||
<header className="modal-card-head">
|
||||
<p className="modal-card-title">{t('auth.header')}</p>
|
||||
</header>
|
||||
<section className="modal-card-body">
|
||||
<Field>{t('auth.message')}</Field>
|
||||
<Field>
|
||||
<input
|
||||
className="input"
|
||||
type="password"
|
||||
placeholder={t('auth.placeholder')}
|
||||
value={password ?? ''}
|
||||
ref={inputRef}
|
||||
onChange={(ev) => setPassword(ev.target.value)}
|
||||
onKeyUp={(ev) => {
|
||||
if (ev.key === 'Enter' || ev.code === 'Enter') {
|
||||
submit();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
</section>
|
||||
<footer className="modal-card-foot">
|
||||
<button className="button is-success" onClick={() => submit()}>
|
||||
{t('auth.button')}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App(): React.ReactElement {
|
||||
const loc = useLocation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const client = useSelector((state: RootState) => state.api.client);
|
||||
const connected = useSelector((state: RootState) => state.api.connected);
|
||||
const connected = useSelector(
|
||||
(state: RootState) => state.api.connectionStatus,
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Create WS client
|
||||
useEffect(() => {
|
||||
if (!client) {
|
||||
dispatch(
|
||||
createWSClient(
|
||||
createWSClient({
|
||||
address:
|
||||
process.env.NODE_ENV === 'development'
|
||||
? 'ws://localhost:4337/ws'
|
||||
: `ws://${loc.host}/ws`,
|
||||
),
|
||||
password: localStorage.password,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (connected === ConnectionStatus.AuthenticationNeeded) {
|
||||
return <AuthModal />;
|
||||
}
|
||||
|
||||
if (!client) {
|
||||
return <div className="container">{t('system.loading')}</div>;
|
||||
}
|
||||
|
@ -108,7 +169,7 @@ export default function App(): React.ReactElement {
|
|||
return (
|
||||
<section className="main-content columns is-fullheight">
|
||||
<section className="notifications">
|
||||
{!connected ? (
|
||||
{connected !== ConnectionStatus.Connected ? (
|
||||
<div className="notification is-danger">
|
||||
{t('system.connection-lost')}
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { RouteComponentProps } from '@reach/router';
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useModule } from '../../lib/react-utils';
|
||||
import apiReducer, { modules } from '../../store/api/reducer';
|
||||
import Field from '../components/Field';
|
||||
|
||||
export default function HTTPPage(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
@ -19,8 +20,7 @@ export default function HTTPPage(
|
|||
return (
|
||||
<>
|
||||
<h1 className="title is-4">{t('http.header')}</h1>
|
||||
<div className="field">
|
||||
<label className="label">{t('http.server-bind')}</label>
|
||||
<Field name={t('http.server-bind')}>
|
||||
<p className="control">
|
||||
<input
|
||||
disabled={busy}
|
||||
|
@ -38,9 +38,28 @@ export default function HTTPPage(
|
|||
}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<label className="label">{t('http.static-content')}</label>
|
||||
<div className="field">
|
||||
</Field>
|
||||
<Field name={t('http.kv-password')}>
|
||||
<p className="control">
|
||||
<input
|
||||
className="input"
|
||||
type="password"
|
||||
disabled={busy}
|
||||
placeholder="None"
|
||||
value={httpConfig?.kv_password ?? ''}
|
||||
onChange={(ev) =>
|
||||
dispatch(
|
||||
apiReducer.actions.httpConfigChanged({
|
||||
...httpConfig,
|
||||
kv_password: ev.target.value,
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
<p className="help">Leave empty to disable authentication</p>
|
||||
</Field>
|
||||
<Field name={t('http.static-content')}>
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
|
@ -57,9 +76,9 @@ export default function HTTPPage(
|
|||
/>{' '}
|
||||
{t('http.enable-static')}
|
||||
</label>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label className="label">{t('http.static-root-path')}</label>
|
||||
</Field>
|
||||
{active && (
|
||||
<Field name={t('http.static-root-path')}>
|
||||
<p className="control">
|
||||
<input
|
||||
className="input"
|
||||
|
@ -76,7 +95,8 @@ export default function HTTPPage(
|
|||
}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</Field>
|
||||
)}
|
||||
<button
|
||||
className="button"
|
||||
onClick={() => {
|
||||
|
|
6
go.mod
6
go.mod
|
@ -17,7 +17,7 @@ require (
|
|||
github.com/nicklaw5/helix v1.25.0
|
||||
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/strimertul/kilovolt/v5 v5.0.1
|
||||
github.com/strimertul/stulbe v0.4.3
|
||||
github.com/strimertul/stulbe-client-go v0.4.0
|
||||
github.com/strimertul/kilovolt/v6 v6.0.1
|
||||
github.com/strimertul/stulbe v0.5.1
|
||||
github.com/strimertul/stulbe-client-go v0.5.0
|
||||
)
|
||||
|
|
14
go.sum
14
go.sum
|
@ -90,6 +90,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD
|
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/nicklaw5/helix v1.13.1/go.mod h1:XeeXY7oY5W+MVMu6wF4qGm8uvjZ1/Nss0FqprVkXKrg=
|
||||
github.com/nicklaw5/helix v1.15.0/go.mod h1:XeeXY7oY5W+MVMu6wF4qGm8uvjZ1/Nss0FqprVkXKrg=
|
||||
github.com/nicklaw5/helix v1.24.2/go.mod h1:XeeXY7oY5W+MVMu6wF4qGm8uvjZ1/Nss0FqprVkXKrg=
|
||||
github.com/nicklaw5/helix v1.25.0 h1:Mrz537izZVsGdM3I46uGAAlslj61frgkhS/9xQqyT/M=
|
||||
github.com/nicklaw5/helix v1.25.0/go.mod h1:yvXZFapT6afIoxnAvlWiJiUMsYnoHl7tNs+t0bloAMw=
|
||||
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yDSOzKFa7WM5bf5itSOo1e3Xh8bm5YCMUXIjQ=
|
||||
|
@ -129,16 +130,17 @@ github.com/strimertul/kilovolt-client-go/v2 v2.0.0/go.mod h1:y98V8uVMiJZhnBLtSVk
|
|||
github.com/strimertul/kilovolt/v3 v3.0.0/go.mod h1:AgfPYRp+kffN64tcqCcQUZdpL/Dm5DGHIYRDm9t3E0Y=
|
||||
github.com/strimertul/kilovolt/v4 v4.0.1 h1:81isohdSixVURO2+dZKKZBPw97HJmNN4/BXn6ADFoWM=
|
||||
github.com/strimertul/kilovolt/v4 v4.0.1/go.mod h1:AO2ZFQtSB+AcjCw0RTkXjbM6XBAjhsXsrRq10BX95kw=
|
||||
github.com/strimertul/kilovolt/v5 v5.0.1 h1:LHAVqb3SrXiew3loTpYuPdz16Nl8/aTReBYj56xwF7I=
|
||||
github.com/strimertul/kilovolt/v5 v5.0.1/go.mod h1:HxfnnlEGhY6p+Im9U7pso07HEV+cXEsJH7uFTM7c6uE=
|
||||
github.com/strimertul/kilovolt/v6 v6.0.0/go.mod h1:O5Rwg8o66omRP4O3qInBKreW9jILZz2MEq4MuotzAXw=
|
||||
github.com/strimertul/kilovolt/v6 v6.0.1 h1:CNiaRsh0wWtZ3yQlz+9RZAtJr3m14ODIa9WQt7NyQ40=
|
||||
github.com/strimertul/kilovolt/v6 v6.0.1/go.mod h1:O5Rwg8o66omRP4O3qInBKreW9jILZz2MEq4MuotzAXw=
|
||||
github.com/strimertul/strimertul v1.3.0/go.mod h1:1pSe9zVWF4BYt56ii1Hg+xTxvtfqfvT4FQ7bYffWsUA=
|
||||
github.com/strimertul/stulbe v0.2.5/go.mod h1:0AsY4OVf1dNCwOn9s7KySuAxJ85w88pXeostu1n9E7w=
|
||||
github.com/strimertul/stulbe v0.4.0/go.mod h1:Pb0UQCKdyES7UKSKm2i2g9parkgXSJAFeMH/LSOSbgQ=
|
||||
github.com/strimertul/stulbe v0.4.3 h1:apDTvFaChCoMxUokc1Y51Wn43hWyf0qqMNkptnlIj/c=
|
||||
github.com/strimertul/stulbe v0.4.3/go.mod h1:Pb0UQCKdyES7UKSKm2i2g9parkgXSJAFeMH/LSOSbgQ=
|
||||
github.com/strimertul/stulbe v0.5.1 h1:CY3s/Vv6I5YkmLcFE3OsY+ysjw+7HywcMcW4EuE6Ejo=
|
||||
github.com/strimertul/stulbe v0.5.1/go.mod h1:fj25VOPKQH2IYcrmjr+bkWffpTiKd7O3ixbe8ZiwbzQ=
|
||||
github.com/strimertul/stulbe-client-go v0.1.0/go.mod h1:KtfuDhxCHZ9DCFHnrBOHqb2Pu9zoj+EqA8ZRIUqLD/w=
|
||||
github.com/strimertul/stulbe-client-go v0.4.0 h1:9DEHnbjU452qFQaK9ilrzydEirpVxwVeiCz7T0kZxEk=
|
||||
github.com/strimertul/stulbe-client-go v0.4.0/go.mod h1:Ssz1mEEWt4y7yj6Dm4aCaEV651Tzz9M+suzhWzC2QqQ=
|
||||
github.com/strimertul/stulbe-client-go v0.5.0 h1:tci0uZ4AiNXb4izCjxL2/qAh1kmR8D74ltZJojgP7Ik=
|
||||
github.com/strimertul/stulbe-client-go v0.5.0/go.mod h1:Ssz1mEEWt4y7yj6Dm4aCaEV651Tzz9M+suzhWzC2QqQ=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.0/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
|
|
8
main.go
8
main.go
|
@ -13,8 +13,6 @@ import (
|
|||
|
||||
"github.com/strimertul/strimertul/modules/http"
|
||||
|
||||
kv "github.com/strimertul/kilovolt/v5"
|
||||
|
||||
"github.com/strimertul/strimertul/database"
|
||||
"github.com/strimertul/strimertul/modules"
|
||||
"github.com/strimertul/strimertul/modules/loyalty"
|
||||
|
@ -118,11 +116,6 @@ func main() {
|
|||
fmt.Printf("It appears this is your first time running %s! Please go to http://%s and make sure to configure anything you want!\n\n", AppTitle, DefaultBind)
|
||||
}
|
||||
|
||||
// Initialize KV (required)
|
||||
hub, err := kv.NewHub(db.Client(), wrapLogger("kv"))
|
||||
failOnError(err, "Could not initialize kilovolt hub")
|
||||
go hub.Run()
|
||||
|
||||
// Get Stulbe config, if enabled
|
||||
var stulbeManager *stulbe.Manager = nil
|
||||
if moduleConfig.EnableStulbe {
|
||||
|
@ -185,7 +178,6 @@ func main() {
|
|||
|
||||
fedir, _ := fs.Sub(frontend, "frontend/dist")
|
||||
httpServer.SetFrontend(fedir)
|
||||
httpServer.SetHub(hub)
|
||||
|
||||
go func() {
|
||||
time.Sleep(time.Second) // THIS IS STUPID
|
||||
|
|
|
@ -6,4 +6,5 @@ type ServerConfig struct {
|
|||
Bind string `json:"bind"`
|
||||
EnableStaticServer bool `json:"enable_static_server"`
|
||||
Path string `json:"path"`
|
||||
KVPassword string `json:"kv_password"`
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
kv "github.com/strimertul/kilovolt/v5"
|
||||
kv "github.com/strimertul/kilovolt/v6"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
|
@ -35,18 +35,25 @@ func NewServer(db *database.DB, log logrus.FieldLogger) (*Server, error) {
|
|||
server: &http.Server{},
|
||||
}
|
||||
err := db.GetJSON(ServerConfigKey, &server.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return server, err
|
||||
server.hub, err = kv.NewHub(db.Client(), kv.HubOptions{
|
||||
Password: server.Config.KVPassword,
|
||||
}, log.WithField("module", "kv"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go server.hub.Run()
|
||||
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetFrontend(files fs.FS) {
|
||||
s.frontend = files
|
||||
}
|
||||
|
||||
func (s *Server) SetHub(hub *kv.Hub) {
|
||||
s.hub = hub
|
||||
}
|
||||
|
||||
func (s *Server) makeMux() *http.ServeMux {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
|
@ -74,11 +81,19 @@ func (s *Server) Listen() error {
|
|||
for _, pair := range changed {
|
||||
if pair.Key == ServerConfigKey {
|
||||
oldBind := s.Config.Bind
|
||||
oldPassword := s.Config.KVPassword
|
||||
err := s.db.GetJSON(ServerConfigKey, &s.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.mux = s.makeMux()
|
||||
// Restart hub if password changed
|
||||
if oldPassword != s.Config.KVPassword {
|
||||
s.hub.SetOptions(kv.HubOptions{
|
||||
Password: s.Config.KVPassword,
|
||||
})
|
||||
}
|
||||
// Restart server if bind changed
|
||||
if oldBind != s.Config.Bind {
|
||||
restart.Set(true)
|
||||
err = s.server.Shutdown(context.Background())
|
||||
|
|
Loading…
Reference in a new issue