v0.1.9 Various bug fixes and UI improvements to route form
This commit is contained in:
parent
bc5743fa05
commit
2eac6fbd3a
|
@ -36,9 +36,9 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
const [containers, setContainers] = React.useState([]);
|
const [containers, setContainers] = React.useState([]);
|
||||||
const [hasPublicPorts, setHasPublicPorts] = React.useState(false);
|
const [hasPublicPorts, setHasPublicPorts] = React.useState(false);
|
||||||
const [isOnBridge, setIsOnBridge] = React.useState(false);
|
const [isOnBridge, setIsOnBridge] = React.useState(false);
|
||||||
const [options, setOptions] = React.useState([]);
|
const [options, setOptions] = React.useState(null);
|
||||||
const [portsOptions, setPortsOptions] = React.useState([]);
|
const [portsOptions, setPortsOptions] = React.useState([]);
|
||||||
const loading = open && options.length === 0;
|
const loading = options === null;
|
||||||
|
|
||||||
const name = "Target"
|
const name = "Target"
|
||||||
const label = "Container Name"
|
const label = "Container Name"
|
||||||
|
@ -50,27 +50,23 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
|
|
||||||
let preview = formik.values[name];
|
let preview = formik.values[name];
|
||||||
|
|
||||||
if(preview && preview.includes("://") && preview.includes(":")) {
|
if(preview) {
|
||||||
let p1_ = preview.split("://")[1]
|
let protocols = preview.split("://")
|
||||||
|
let p1_ = protocols.length > 1 ? protocols[1] : protocols[0]
|
||||||
|
console.log("p1_", p1_)
|
||||||
targetResult = {
|
targetResult = {
|
||||||
container: '/' + p1_.split(":")[0],
|
container: '/' + p1_.split(":")[0],
|
||||||
port: p1_.split(":")[1],
|
port: p1_.split(":")[1],
|
||||||
protocol: preview.split("://")[0],
|
protocol: preview.split("://")[0],
|
||||||
containerObject: containers.find((container) => container.Names[0] === '/' + p1_.split(":")[0]),
|
containerObject: !loading && containers.find((container) => container.Names[0] === '/' + p1_.split(":")[0]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTarget() {
|
function getTarget() {
|
||||||
return targetResult.protocol + "://" + targetResult.container.replace("/", "") + ":" + targetResult.port
|
return targetResult.protocol + (targetResult.protocol != '' ? "://" : '') + targetResult.container.replace("/", "") + ":" + targetResult.port
|
||||||
}
|
}
|
||||||
|
|
||||||
const onContainerChange = (newContainer) => {
|
const postContainerChange = (newContainer) => {
|
||||||
targetResult.container = newContainer.Names[0]
|
|
||||||
targetResult.containerObject = newContainer
|
|
||||||
targetResult.port = ''
|
|
||||||
targetResult.protocol = 'http'
|
|
||||||
formik.setFieldValue(name, getTarget())
|
|
||||||
|
|
||||||
let portsTemp = []
|
let portsTemp = []
|
||||||
newContainer.Ports.forEach((port) => {
|
newContainer.Ports.forEach((port) => {
|
||||||
portsTemp.push(port.PrivatePort)
|
portsTemp.push(port.PrivatePort)
|
||||||
|
@ -85,6 +81,17 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onContainerChange = (newContainer) => {
|
||||||
|
if(loading) return;
|
||||||
|
targetResult.container = newContainer.Names[0]
|
||||||
|
targetResult.containerObject = newContainer
|
||||||
|
targetResult.port = ''
|
||||||
|
targetResult.protocol = 'http'
|
||||||
|
formik.setFieldValue(name, getTarget())
|
||||||
|
|
||||||
|
postContainerChange(newContainer)
|
||||||
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if(lockTarget) {
|
if(lockTarget) {
|
||||||
onContainerChange(TargetContainer)
|
onContainerChange(TargetContainer)
|
||||||
|
@ -102,12 +109,14 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
const res = await API.docker.list()
|
const res = await API.docker.list()
|
||||||
setContainers(res.data);
|
setContainers(res.data);
|
||||||
|
|
||||||
|
|
||||||
let names = res.data.map((container) => container.Names[0])
|
let names = res.data.map((container) => container.Names[0])
|
||||||
|
|
||||||
if (active) {
|
if (active) {
|
||||||
setOptions([...names]);
|
setOptions([...names]);
|
||||||
}
|
}
|
||||||
|
if (targetResult.container !== 'null') {
|
||||||
|
postContainerChange(res.data.find((container) => container.Names[0] === targetResult.container))
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -124,7 +133,7 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
return ( <Grid item xs={12}>
|
return ( <Grid item xs={12}>
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
<InputLabel htmlFor={name + "-autocomplete"}>{label}</InputLabel>
|
<InputLabel htmlFor={name + "-autocomplete"}>{label}</InputLabel>
|
||||||
<Autocomplete
|
{!loading && <Autocomplete
|
||||||
id={name + "-autocomplete"}
|
id={name + "-autocomplete"}
|
||||||
open={open}
|
open={open}
|
||||||
disabled={lockTarget}
|
disabled={lockTarget}
|
||||||
|
@ -147,7 +156,7 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
loading={loading}
|
loading={loading}
|
||||||
freeSolo={true}
|
freeSolo={true}
|
||||||
placeholder={"Please select a container"}
|
placeholder={"Please select a container"}
|
||||||
defaultValue={lockTarget ? TargetContainer : targetResult.containerObject}
|
value={lockTarget ? TargetContainer : (targetResult.containerObject || {Names: ['...']})}
|
||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField
|
<TextField
|
||||||
{...params}
|
{...params}
|
||||||
|
@ -162,7 +171,7 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>}
|
||||||
|
|
||||||
{(portsOptions.length > 0) ? (<>
|
{(portsOptions.length > 0) ? (<>
|
||||||
<InputLabel htmlFor={name + "-port"}>Container Port</InputLabel>
|
<InputLabel htmlFor={name + "-port"}>Container Port</InputLabel>
|
||||||
|
@ -171,7 +180,7 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
name={name + "-port"}
|
name={name + "-port"}
|
||||||
id={name + "-port"}
|
id={name + "-port"}
|
||||||
defaultValue={targetResult.port}
|
value={targetResult.port}
|
||||||
select
|
select
|
||||||
placeholder='Select a port'
|
placeholder='Select a port'
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
|
@ -184,24 +193,24 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
{option}
|
{option}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</TextField></>) : ''}
|
</TextField>
|
||||||
|
{targetResult.port == '' && <FormHelperText error id="standard-weight-helper-text-name-login">
|
||||||
|
Please select a port
|
||||||
|
</FormHelperText>}
|
||||||
|
</>) : ''}
|
||||||
|
|
||||||
|
|
||||||
{(portsOptions.length > 0) ? (<>
|
{(portsOptions.length > 0) ? (<>
|
||||||
<Grid item xs={12}>
|
<InputLabel htmlFor={name + "-protocol"}>Container Protocol (use HTTP if unsure)</InputLabel>
|
||||||
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
|
<TextField
|
||||||
<FormControlLabel
|
type="text"
|
||||||
type="checkbox"
|
|
||||||
name={name + "-protocol"}
|
name={name + "-protocol"}
|
||||||
control={<Checkbox size="large" />}
|
defaultValue={targetResult.protocol}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
targetResult.protocol = event.target.checked ? "https" : "http"
|
targetResult.protocol = event.target.value && event.target.value.toLowerCase()
|
||||||
formik.setFieldValue(name, getTarget())
|
formik.setFieldValue(name, getTarget())
|
||||||
}}
|
}}
|
||||||
label={"Container uses HTTPS internally (leave unchecked if not sure, they usually don't)"}
|
|
||||||
/>
|
/>
|
||||||
</Stack>
|
|
||||||
</Grid>
|
|
||||||
</>) : ''}
|
</>) : ''}
|
||||||
|
|
||||||
<InputLabel htmlFor={name}>Result Target Preview</InputLabel>
|
<InputLabel htmlFor={name}>Result Target Preview</InputLabel>
|
||||||
|
@ -212,6 +221,12 @@ export function CosmosContainerPicker({formik, lockTarget, TargetContainer}) {
|
||||||
value={formik.values[name]}
|
value={formik.values[name]}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{formik.errors[name] && (
|
||||||
|
<FormHelperText error id="standard-weight-helper-text-name-login">
|
||||||
|
{formik.errors[name]}
|
||||||
|
</FormHelperText>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
|
|
@ -38,12 +38,7 @@ export const CosmosInputText = ({ name, style, multiline, type, placeholder, onC
|
||||||
name={name}
|
name={name}
|
||||||
multiline={multiline}
|
multiline={multiline}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
onChange={(...e) => {
|
onChange={formik.handleChange}
|
||||||
if (onChange) {
|
|
||||||
onChange(...e);
|
|
||||||
}
|
|
||||||
formik.handleChange(...e);
|
|
||||||
}}
|
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
fullWidth
|
fullWidth
|
||||||
error={Boolean(formik.touched[name] && formik.errors[name])}
|
error={Boolean(formik.touched[name] && formik.errors[name])}
|
||||||
|
@ -172,6 +167,11 @@ export const CosmosCheckbox = ({ name, label, formik, style }) => {
|
||||||
style={style}
|
style={style}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
{formik.touched[name] && formik.errors[name] && (
|
||||||
|
<FormHelperText error id="standard-weight-helper-text-name-login">
|
||||||
|
{formik.errors[name]}
|
||||||
|
</FormHelperText>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ import {
|
||||||
import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
|
import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
|
||||||
import AnimateButton from '../../../components/@extended/AnimateButton';
|
import AnimateButton from '../../../components/@extended/AnimateButton';
|
||||||
import RestartModal from './restart';
|
import RestartModal from './restart';
|
||||||
import RouteManagement from './routeman';
|
import RouteManagement, {ValidateRoute} from './routeman';
|
||||||
|
import { map } from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
const ProxyManagement = () => {
|
const ProxyManagement = () => {
|
||||||
|
@ -36,6 +37,7 @@ const ProxyManagement = () => {
|
||||||
const [config, setConfig] = React.useState(null);
|
const [config, setConfig] = React.useState(null);
|
||||||
const [openModal, setOpenModal] = React.useState(false);
|
const [openModal, setOpenModal] = React.useState(false);
|
||||||
const [error, setError] = React.useState(null);
|
const [error, setError] = React.useState(null);
|
||||||
|
const [submitErrors, setSubmitErrors] = React.useState([]);
|
||||||
|
|
||||||
function updateRoutes(routes) {
|
function updateRoutes(routes) {
|
||||||
let con = {
|
let con = {
|
||||||
|
@ -52,6 +54,14 @@ const ProxyManagement = () => {
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanRoutes(config) {
|
||||||
|
config.HTTPConfig.ProxyConfig.Routes = config.HTTPConfig.ProxyConfig.Routes.map((r) => {
|
||||||
|
delete r._hasErrors;
|
||||||
|
return r;
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
function refresh() {
|
function refresh() {
|
||||||
API.config.get().then((res) => {
|
API.config.get().then((res) => {
|
||||||
setConfig(res.data);
|
setConfig(res.data);
|
||||||
|
@ -85,6 +95,13 @@ const ProxyManagement = () => {
|
||||||
refresh();
|
refresh();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const testRoute = (route) => {
|
||||||
|
try {
|
||||||
|
ValidateRoute.validateSync(route);
|
||||||
|
} catch (e) {
|
||||||
|
return e.errors;
|
||||||
|
}
|
||||||
|
}
|
||||||
let routes = config && (config.HTTPConfig.ProxyConfig.Routes || []);
|
let routes = config && (config.HTTPConfig.ProxyConfig.Routes || []);
|
||||||
|
|
||||||
return <div style={{ maxWidth: '1000px', margin: '' }}>
|
return <div style={{ maxWidth: '1000px', margin: '' }}>
|
||||||
|
@ -92,7 +109,7 @@ const ProxyManagement = () => {
|
||||||
refresh();
|
refresh();
|
||||||
}}>Refresh</Button>
|
}}>Refresh</Button>
|
||||||
<Button variant="contained" color="primary" startIcon={<PlusCircleOutlined />} onClick={() => {
|
<Button variant="contained" color="primary" startIcon={<PlusCircleOutlined />} onClick={() => {
|
||||||
routes.push({
|
routes.unshift({
|
||||||
Name: 'New Route',
|
Name: 'New Route',
|
||||||
Description: 'New Route',
|
Description: 'New Route',
|
||||||
Mode: "SERVAPP",
|
Mode: "SERVAPP",
|
||||||
|
@ -114,7 +131,7 @@ const ProxyManagement = () => {
|
||||||
{config && <>
|
{config && <>
|
||||||
<RestartModal openModal={openModal} setOpenModal={setOpenModal} />
|
<RestartModal openModal={openModal} setOpenModal={setOpenModal} />
|
||||||
{routes && routes.map((route,key) => (<>
|
{routes && routes.map((route,key) => (<>
|
||||||
<RouteManagement routeConfig={route}
|
<RouteManagement key={key} routeConfig={route}
|
||||||
setRouteConfig={(newRoute) => {
|
setRouteConfig={(newRoute) => {
|
||||||
routes[key] = newRoute;
|
routes[key] = newRoute;
|
||||||
}}
|
}}
|
||||||
|
@ -133,13 +150,30 @@ const ProxyManagement = () => {
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
|
<Stack spacing={1}>
|
||||||
|
{submitErrors.map((err) => {
|
||||||
|
return <Alert severity="error">{err}</Alert>
|
||||||
|
})}
|
||||||
<AnimateButton>
|
<AnimateButton>
|
||||||
<Button
|
<Button
|
||||||
disableElevation
|
disableElevation
|
||||||
disabled={false}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
API.config.set(updateRoutes(routes)).then(() => {
|
if(routes.some((route, key) => {
|
||||||
|
let errors = testRoute(route);
|
||||||
|
if (errors && errors.length > 0) {
|
||||||
|
errors = errors.map((err) => {
|
||||||
|
return `${route.Name}: ${err}`;
|
||||||
|
});
|
||||||
|
setSubmitErrors(errors);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
setSubmitErrors([]);
|
||||||
|
}
|
||||||
|
API.config.set(cleanRoutes(updateRoutes(routes))).then(() => {
|
||||||
setOpenModal(true);
|
setOpenModal(true);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
@ -154,6 +188,7 @@ const ProxyManagement = () => {
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</AnimateButton>
|
</AnimateButton>
|
||||||
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
</MainCard>
|
</MainCard>
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,32 @@ import { CosmosCheckbox, CosmosCollapse, CosmosFormDivider, CosmosInputText, Cos
|
||||||
import { DownOutlined, UpOutlined, CheckOutlined, DeleteOutlined } from '@ant-design/icons';
|
import { DownOutlined, UpOutlined, CheckOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||||
import { CosmosContainerPicker } from './containerPicker';
|
import { CosmosContainerPicker } from './containerPicker';
|
||||||
|
|
||||||
|
export const ValidateRoute = Yup.object().shape({
|
||||||
|
Name: Yup.string().required('Name is required'),
|
||||||
|
Mode: Yup.string().required('Mode is required'),
|
||||||
|
Target: Yup.string().required('Target is required').when('Mode', {
|
||||||
|
is: 'SERVAPP',
|
||||||
|
then: Yup.string().matches(/:[0-9]+$/, 'Invalid Target, must have a port'),
|
||||||
|
}),
|
||||||
|
|
||||||
|
Host: Yup.string().when('UseHost', {
|
||||||
|
is: true,
|
||||||
|
then: Yup.string().required('Host is required')
|
||||||
|
.matches(/[\.|\:]/, 'Host must be full domain ([sub.]domain.com) or an IP')
|
||||||
|
}),
|
||||||
|
|
||||||
|
PathPrefix: Yup.string().when('UsePathPrefix', {
|
||||||
|
is: true,
|
||||||
|
then: Yup.string().required('Path Prefix is required').matches(/^\//, 'Path Prefix must start with / (e.g. /api). Do not include a domain/subdomain in it, use the Host for this.')
|
||||||
|
}),
|
||||||
|
|
||||||
|
UseHost: Yup.boolean().when('UsePathPrefix',
|
||||||
|
{
|
||||||
|
is: false,
|
||||||
|
then: Yup.boolean().oneOf([true], 'Source must at least be either Host or Path Prefix')
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
const RouteManagement = ({ routeConfig, TargetContainer, noControls=false, lockTarget=false, setRouteConfig, up, down, deleteRoute }) => {
|
const RouteManagement = ({ routeConfig, TargetContainer, noControls=false, lockTarget=false, setRouteConfig, up, down, deleteRoute }) => {
|
||||||
const [confirmDelete, setConfirmDelete] = React.useState(false);
|
const [confirmDelete, setConfirmDelete] = React.useState(false);
|
||||||
|
|
||||||
|
@ -54,15 +80,14 @@ const RouteManagement = ({ routeConfig, TargetContainer, noControls=false, lockT
|
||||||
ThrottlePerMinute: routeConfig.ThrottlePerMinute,
|
ThrottlePerMinute: routeConfig.ThrottlePerMinute,
|
||||||
CORSOrigin: routeConfig.CORSOrigin,
|
CORSOrigin: routeConfig.CORSOrigin,
|
||||||
}}
|
}}
|
||||||
validationSchema={Yup.object().shape({
|
validateOnChange={false}
|
||||||
|
validationSchema={ValidateRoute}
|
||||||
})}
|
|
||||||
validate={(values) => {
|
|
||||||
setRouteConfig(values);
|
|
||||||
}}
|
|
||||||
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
|
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
|
||||||
return false;
|
return false;
|
||||||
}}
|
}}
|
||||||
|
validate={(values) => {
|
||||||
|
//setRouteConfig(values);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{(formik) => (
|
{(formik) => (
|
||||||
<form noValidate onSubmit={formik.handleSubmit}>
|
<form noValidate onSubmit={formik.handleSubmit}>
|
||||||
|
@ -76,6 +101,11 @@ const RouteManagement = ({ routeConfig, TargetContainer, noControls=false, lockT
|
||||||
</div>
|
</div>
|
||||||
}>
|
}>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
|
{formik.errors.submit && (
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<FormHelperText error>{formik.errors.submit}</FormHelperText>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
|
||||||
<CosmosInputText
|
<CosmosInputText
|
||||||
name="Name"
|
name="Name"
|
||||||
|
@ -108,6 +138,7 @@ const RouteManagement = ({ routeConfig, TargetContainer, noControls=false, lockT
|
||||||
["PROXY", "Proxy"],
|
["PROXY", "Proxy"],
|
||||||
["STATIC", "Static Folder"],
|
["STATIC", "Static Folder"],
|
||||||
["SPA", "Single Page Application"],
|
["SPA", "Single Page Application"],
|
||||||
|
["REDIRECT", "Redirection"]
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cosmos-server",
|
"name": "cosmos-server",
|
||||||
"version": "0.1.8",
|
"version": "0.1.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "test-server.js",
|
"main": "test-server.js",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
@ -70,7 +70,7 @@ Authentication is very hard (how do you check the password match? What encryptio
|
||||||
Installation is simple using Docker:
|
Installation is simple using Docker:
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -d -p 80:80 -p 443:443 --name cosmos-server --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /path/to/cosmos/config:/config azukaar/cosmos-server:latest
|
docker run -d -p 80:80 -p 443:443 --name cosmos-server -h cosmos-server --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /path/to/cosmos/config:/config azukaar/cosmos-server:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Once installed, simply go to `http://your-ip` and follow the instructions of the setup wizard.
|
Once installed, simply go to `http://your-ip` and follow the instructions of the setup wizard.
|
||||||
|
|
|
@ -63,21 +63,6 @@ func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination htt
|
||||||
}
|
}
|
||||||
destination = http.StripPrefix(route.PathPrefix, destination)
|
destination = http.StripPrefix(route.PathPrefix, destination)
|
||||||
}
|
}
|
||||||
timeout := route.Timeout
|
|
||||||
|
|
||||||
if(timeout == 0) {
|
|
||||||
timeout = 10000
|
|
||||||
}
|
|
||||||
|
|
||||||
throttlePerMinute := route.ThrottlePerMinute
|
|
||||||
|
|
||||||
throtthleTime := 1*time.Minute
|
|
||||||
|
|
||||||
// lets do something better later to disable throttle
|
|
||||||
if(throttlePerMinute == 0) {
|
|
||||||
throttlePerMinute = 99999999
|
|
||||||
throtthleTime = 1*time.Second
|
|
||||||
}
|
|
||||||
|
|
||||||
originCORS := route.CORSOrigin
|
originCORS := route.CORSOrigin
|
||||||
|
|
||||||
|
@ -93,11 +78,17 @@ func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination htt
|
||||||
utils.Warn("PathPrefix is used, but StripPathPrefix is false. The route mode is " + (string)(route.Mode) + ". This will likely cause issues with the route. Ignore this warning if you know what you are doing.")
|
utils.Warn("PathPrefix is used, but StripPathPrefix is false. The route mode is " + (string)(route.Mode) + ". This will likely cause issues with the route. Ignore this warning if you know what you are doing.")
|
||||||
}
|
}
|
||||||
|
|
||||||
origin.Handler(
|
timeout := route.Timeout
|
||||||
tokenMiddleware(route.AuthEnabled)(
|
|
||||||
utils.CORSHeader(originCORS)(
|
if(timeout > 0) {
|
||||||
utils.MiddlewareTimeout(timeout * time.Millisecond)(
|
destination = utils.MiddlewareTimeout(timeout * time.Millisecond)(destination)
|
||||||
httprate.Limit(throttlePerMinute, throtthleTime,
|
}
|
||||||
|
|
||||||
|
throttlePerMinute := route.ThrottlePerMinute
|
||||||
|
|
||||||
|
if(throttlePerMinute > 0) {
|
||||||
|
throtthleTime := time.Minute
|
||||||
|
destination = httprate.Limit(throttlePerMinute, throtthleTime,
|
||||||
httprate.WithKeyFuncs(httprate.KeyByIP),
|
httprate.WithKeyFuncs(httprate.KeyByIP),
|
||||||
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
|
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
|
||||||
utils.Error("Too many requests. Throttling", nil)
|
utils.Error("Too many requests. Throttling", nil)
|
||||||
|
@ -105,7 +96,10 @@ func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination htt
|
||||||
http.StatusTooManyRequests, "HTTP003")
|
http.StatusTooManyRequests, "HTTP003")
|
||||||
return
|
return
|
||||||
}),
|
}),
|
||||||
)(destination)))))
|
)(destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
origin.Handler(tokenMiddleware(route.AuthEnabled)(utils.CORSHeader(originCORS)((destination))))
|
||||||
|
|
||||||
utils.Log("Added route: ["+ (string)(route.Mode) + "] " + route.Host + route.PathPrefix + " to " + route.Target + "")
|
utils.Log("Added route: ["+ (string)(route.Mode) + "] " + route.Host + route.PathPrefix + " to " + route.Target + "")
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ func MiddlewareTimeout(timeout time.Duration) func(next http.Handler) http.Handl
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
w.Header().Set("X-Timeout-Duration", timeout.String())
|
||||||
|
|
||||||
r = r.WithContext(ctx)
|
r = r.WithContext(ctx)
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue